Удалить лишние (повторяющиеся) объекты из списка объектов, которые не являются точными дубликатами

#c# #list #algorithm #foreach #duplicates

#c# #Список #алгоритм #foreach #дубликаты

Вопрос:

У меня есть список объектов на C #, которые имеют несколько свойств (цена, цвет, описание и дата указаны, но НЕ уникальный идентификатор). Конечная цель — отфильтровать список — если два объекта имеют одинаковую цену и цвет, мы проверяем, содержат ли описания более 50% совпадающих слов (но не совпадают, поскольку они являются бесплатным вводом). Кроме того, иногда dateAdded может быть пустым, поэтому предпочтительно, если есть 2 «дубликата», мы сохраняем тот, у которого есть dateAdded .

Итак

  1. [100 долларов США, красный, «красивая хлопковая рубашка», «29.10.2020»]

и

  1. [100 долларов США, красный, «хлопковая рубашка», «01/01/0001»]

считаются дубликатами, и тот, у которого нет даты, должен быть удален из списка.

Я знаю, что простое удаление дубликатов может быть достигнуто с помощью linq

 var noDups = myList.GroupBy(x => x.Id).Select(x => x.First()).ToList();
  

но если я выполню группировку в моем случае, я не уверен, как проверить описание / дату позже.

Кроме того, я знаю, что это можно решить с помощью нескольких циклов foreach и временных списков, но я боюсь, что это становится слишком сложным таким образом

Я пробовал работать с одним и тем же списком — динамически удалять элементы, но после завершения обоих циклов элементы отсутствуют.

 foreach (var prop in listOfProducts)
            {
                foreach (var secondProp in listOfProducts.Where(x => x.ListingID != prop.ListingID).ToList())
                {
                    if (prop.Price == secondProp.Price amp;amp; prop.Color == secondProp.Color )
                    {
                      
                        var propSplitDesc = prop.Description.Split().ToList();
                        var secondPropSplitDesc = secondProp.Description.Split().ToList();
                        var descLength = propSplitDesc.Count > secondPropSplitDesc.Count
                            ? propSplitDesc.Count
                            : secondPropSplitDesc.Count;
                        var wordsMatching = propSplitDesc.Intersect(secondPropSplitDesc).ToList();
                        if (wordsMatching.Count >= (double)descLength / 2)
                        {
                            finalProp.ComaprableProperties.Remove(prop.DateAdded == DateTime.MinValue
                              ? prop
                              : secondProp);
                        }
                    }
                }
            }
  

Есть ли что-нибудь не слишком сложное, что можно сделать, или можно как-то использовать linq?

Ответ №1:

Я не тестировал это, но я думаю, что следующее должно сработать для вас. Тогда вам решать, легче ли это читать или нет:

 var noDups = myList.GroupBy(x => new { x.Color, x.Price })
    .SelectMany(group => 
    {
        var candidates = group.ToList();
        return candidates.Where(x => candidates
            .Where(y => y != x) // Don't compare against itself
            .All(y =>
                // Other candidate does not match by words
                !HasMoreThanHalfMatchingWords(x, y)
                // ... or this one does have a proper date
                || x.DateAdded != DateTime.MinValue));
    });

// In some other place...
bool HasMoreThanHalfMatchingWords(string desc1, string desc2)
{
    // Logic to compare if the strings contain more than 50% matching words
}
  

Соображения о ваших определениях

Я думаю, что у вас есть недостаток в вашем определении «дубликата». Рассмотрим следующий пример:

ItemA

  • Описание: «бурая лиса перепрыгнула через ленивую собаку»
  • Дата добавления: 29.10.2020

itemB

  • Описание «прыгнул бурый лис»
  • Дата добавления: 29.10.2020

ItemC

  • Описание: «перепрыгнул через ленивую собаку»
  • Дата добавления: 01/01/0001

Какие элементы считаются дублированными, а какие окажутся в конечном списке?

A и B разделяют 50% слов. A и C делают то же самое.

Следует ли сохранять только A, даже если B и C выглядят по-разному, что означает, что вы теряете элементы, которые не дублируются?

Должны ли вы сохранить оба A и B? A потому что он имеет «dateAdded» и является дубликатом C, и B потому что, ну … это не «дубликат» C, поэтому вы должны сохранить один из них?

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

1. Мой пример был немного глупым, но в реальном сценарии у меня есть список, в котором не более 2 похожих. Итак, если есть список из 50 объектов, 10 из которых найдены дважды (но с другим описанием или / и добавленной датой), мне нужно, чтобы в списке после фильтрации было 40. Итак, 10 «дубликатов» удалены, и поскольку эти 10 присутствуют дважды — если возможно, те, у которых нет добавленной даты, должны исчезнуть. Игнорируйте условие проверки «дублирования», с чем я в основном борюсь, так это с созданием списка. В упомянутом вами примере я бы удалил как B, так и C, но такого сценария не произойдет (> 2 похожих)

2. @Filip5991 В моем примере также не более 2 похожих объектов 😉 Но в любом случае… Я добавил пример, который, я считаю, должен сработать для вас. Однако вам придется это протестировать.