Найдите объект с самой длинной строкой

#c# #linq

#c# #linq

Вопрос:

Я получаю список объектов из внешней службы вида:

 [
    {
      'Sentence': 'C13 can travel by own car on road.',
      'Subject': 'C13',
      'Object': 'car',
      'Relation': 'CAN_TRAVEL_BY'
    },
    {
      'Sentence': 'C13 can travel by own car on road.',
      'Subject': 'C13',
      'Object': 'own car',
      'Relation': 'CAN_TRAVEL_BY'
    },
    {
      'Sentence': 'C13 can travel by own car on road.',
      'Subject': 'C13',
      'Object': 'road',
      'Relation': 'CAN_TRAVEL_ON'
    },
    {
      'Sentence': 'Kunal Mukherjee can travel by own car on road.',
      'Subject': 'Kunal',
      'Object': 'own car',
      'Relation': 'CAN_TRAVEL_BY'
    },
    {
      'Sentence': 'Kunal Mukherjee can travel by own car on road.',
      'Subject': 'Kunal Mukherjee',
      'Object': 'own car',
      'Relation': 'CAN_TRAVEL_BY'
    }
]
  

Итак, моя цель — отфильтровать объекты из ответа, которые содержат друг друга,

 {
  'Sentence': 'Kunal Mukherjee can travel by own car on road.',
  'Subject': 'Kunal',
  'Object': 'own car',
  'Relation': 'CAN_TRAVEL_BY'
},
{
  'Sentence': 'Kunal Mukherjee can travel by own car on road.',
  'Subject': 'Kunal Mukherjee',
  'Object': 'own car',
  'Relation': 'CAN_TRAVEL_BY'
}
  

В приведенных выше объектах в Subject свойстве есть самая длинная общая строка Kunal Mukherjee , поэтому фильтровать нужно только этот объект.

Другой пример:

 {
  'Sentence': 'C13 can travel by own car on road.',
  'Subject': 'C13',
  'Object': 'car',
  'Relation': 'CAN_TRAVEL_BY'
},
{
  'Sentence': 'C13 can travel by own car on road.',
  'Subject': 'C13',
  'Object': 'own car',
  'Relation': 'CAN_TRAVEL_BY'
}
  

Здесь в Object свойстве own car находится самая длинная общая строка из двух, поэтому ее следует взять.


Итак, окончательный отфильтрованный список должен выглядеть примерно так:

 [
    {
      'Sentence': 'C13 can travel by own car on road.',
      'Subject': 'C13',
      'Object': 'own car',
      'Relation': 'CAN_TRAVEL_BY'
    },
    {
      'Sentence': 'C13 can travel by own car on road.',
      'Subject': 'C13',
      'Object': 'road',
      'Relation': 'CAN_TRAVEL_ON'
    },
    {
      'Sentence': 'Kunal Mukherjee can travel by own car on road.',
      'Subject': 'Kunal Mukherjee',
      'Object': 'own car',
      'Relation': 'CAN_TRAVEL_BY'
    }
]
  

Итак, я пытаюсь таким образом сравнить каждый ith и i 1th элемент для правила, которое:

  • Если ith элемент Subject содержит i 1th element Subject , возьмите его и наоборот.
  • Если ith элемент Object содержит i 1th element Object , возьмите его и наоборот.

но он не отображается правильно.

 static void Main(string[] args)
{
    string data = @"[
                    {
                      'Sentence': 'C13 can travel by own car on road.',
                      'Subject': 'C13',
                      'Object': 'car',
                      'Relation': 'CAN_TRAVEL_BY'
                    },
                    {
                      'Sentence': 'C13 can travel by own car on road.',
                      'Subject': 'C13',
                      'Object': 'own car',
                      'Relation': 'CAN_TRAVEL_BY'
                    },
                    {
                      'Sentence': 'C13 can travel by own car on road.',
                      'Subject': 'C13',
                      'Object': 'road',
                      'Relation': 'CAN_TRAVEL_ON'
                    },
                    {
                      'Sentence': 'Kunal Mukherjee can travel by own car on road.',
                      'Subject': 'Kunal',
                      'Object': 'own car',
                      'Relation': 'CAN_TRAVEL_BY'
                    },
                    {
                      'Sentence': 'Kunal Mukherjee can travel by own car on road.',
                      'Subject': 'Kunal Mukherjee',
                      'Object': 'own car',
                      'Relation': 'CAN_TRAVEL_BY'
                    }
                  ]";

    List<JObject> js = JsonConvert.DeserializeObject<List<JObject>>(data);

    var pairs = js.Take(js.Count - 1).Select((x, i) =>
    {
        string aSubj = js[i]["Subject"].ToString();
        string bSubj = js[i   1]["Subject"].ToString();


        string aObj = js[i]["Object"].ToString();
        string bObj = js[i   1]["Object"].ToString();

        if ((aSubj.Length > bSubj.Length amp;amp; aSubj.Contains(bSubj)) || (aObj.Length > bObj.Length amp;amp; aObj.Contains(bObj)))
        {
            return js[i];
        }
        if ((aSubj.Length > bSubj.Length amp;amp; aSubj.Contains(bSubj)) || (bObj.Length > aObj.Length amp;amp; bObj.Contains(aObj)))
        {
            return js[i   1];
        }

        return js[i];
    }).ToList();
}
  

Это .NET fiddle для проверки этого.

Я буду признателен за любую помощь, которая поможет мне решить эту проблему.

Комментарии:

1. Что, если у одного элемента длина больше, Subject а у другого элемента длиннее Object ?

2. Извините, но неясно, что именно вы ищете… Я понимаю, что вы получаете, но я не понимаю, чего вы хотите от этих данных…

3. Идея смежна, Subject(s) и Object(s) необходимо сравнивать для самых длинных совпадений

4. @KunalMukherjee adjacent в вашем вопросе не существует критериев

5. @MartinVerjans Я создаю графическую базу данных, используя естественный язык и разделяя их с помощью стэнфордского сервиса CoreNLP, который выдает мне ответ в следующей форме

Ответ №1:

Вы можете создать метод (расширения), который уменьшает (фильтрует) ваши элементы:

 public static IEnumerable<Item> Reduce(this IEnumerable<Item> items)
{
    using (var iterator = items.GetEnumerator())
    {
        if (!iterator.MoveNext())
            yield break;

        var previous = iterator.Current;

        while (iterator.MoveNext())
        {
            var next = iterator.Current;
            var containsPrevious =
                previous.Sentence == next.Sentence amp;amp;
                next.Subject.Contains(previous.Subject) amp;amp;
                next.Object.Contains(previous.Object);

            if (!containsPrevious)
                yield return previous;

            previous = next;
        }

        yield return previous;
    }
}
  

Правило простое — когда соседние элементы содержат одно и то же предложение, а последний элемент включает субъект и объект предыдущего элемента, тогда отбросьте первый элемент из результатов.

Использование простое:

 var result = JsonConvert.DeserializeObject<List<Item>>(data).Reduce();
  

Обратите внимание, что вам нужен Item класс (рассмотрите возможность использования лучших имен)

 public class Item
{
    public string Sentence { get; set; }
    public string Subject { get; set; }
    public string Object { get; set; }
    public string Relation { get; set; }
}
  

Выходной сигнал:

 [
  {
    "Sentence": "C13 can travel by own car on road.",
    "Subject": "C13",
    "Object": "own car",
    "Relation": "CAN_TRAVEL_BY"
  },
  {
    "Sentence": "C13 can travel by own car on road.",
    "Subject": "C13",
    "Object": "road",
    "Relation": "CAN_TRAVEL_ON"
  },
  {
    "Sentence": "Kunal Mukherjee can travel by own car on road.",
    "Subject": "Kunal Mukherjee",
    "Object": "own car",
    "Relation": "CAN_TRAVEL_BY"
  }
]
  

Комментарии:

1. 2 вопроса, 1) while (iterator.MoveNext()) как итератор возвращается назад? 2) Почему previous = next;

2. Итератор переходит только вперед, поэтому я сохраняю предыдущий элемент. previous = next сохранить текущий элемент для следующей итерации