问题描述
我有一个C#对象列表,这些对象具有多个属性(价格,颜色,描述和dateAdded,但否是唯一的ID)。最终目标是过滤列表-如果两个对象的价格和颜色相同,我们将检查描述中是否包含超过50%的匹配词(但不相同,因为它们是免费条目)。此外,有时dateAdded可以为空,因此,如果有两个“重复项”,我们最好将一个 with dateAdded保留。
所以
- [$ 100,红色,“美丽的棉衬衫”,“ 10/29/2020”]
和
- [$ 100,红色,“棉衬衫”,“ 01/01/0001”]
被视为重复项,没有日期的应从列表中删除。
我知道使用linq's可以实现简单的重复删除
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 && 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?
解决方法
我还没有测试过,但是我认为以下应该适合您。然后由您决定是否更容易阅读:
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
- 描述:“棕狐跳过了懒狗”
- 添加日期:2020年10月29日
ItemB
- 描述“褐狐跳了起来”
- 添加日期:2020年10月29日
ItemC
- 描述:“跳过懒狗”
- 添加日期:01/01/0001
哪些项被视为重复项,哪些项将最终出现在最终列表中?
A和B共享50%的单词。 A和C也是如此。
即使B和C看起来不同,您也应该只保留A,这意味着您丢失了没有重复的项目吗?
您应该同时保留A和B吗? A是因为它具有“ dateAdded”并且是C的副本,而B是因为...不是C的“副本”,所以您应该保留其中一个?