#c# #list #algorithm #foreach #duplicates
#c# #Список #алгоритм #foreach #дубликаты
Вопрос:
У меня есть список объектов на C #, которые имеют несколько свойств (цена, цвет, описание и дата указаны, но НЕ уникальный идентификатор). Конечная цель — отфильтровать список — если два объекта имеют одинаковую цену и цвет, мы проверяем, содержат ли описания более 50% совпадающих слов (но не совпадают, поскольку они являются бесплатным вводом). Кроме того, иногда dateAdded может быть пустым, поэтому предпочтительно, если есть 2 «дубликата», мы сохраняем тот, у которого есть dateAdded .
Итак
- [100 долларов США, красный, «красивая хлопковая рубашка», «29.10.2020»]
и
- [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 похожих объектов 😉 Но в любом случае… Я добавил пример, который, я считаю, должен сработать для вас. Однако вам придется это протестировать.