你忘了说为什么要保留第 444 项而不是第 111 项,而不是相反。
LINQ 是为查询数据而开发的。 LINQ 永远不会更改原始源序列。
您可以使用 LINQ 查询您要移除的项目,然后使用 foreach 将项目一一移除。
查询具有重复项的项目很容易。如果您更频繁地需要此功能,请考虑为此创建一个扩展功能:
static IEnumerable<IGrouping<TSource, TKey>> GetDuplicates<TSource>(
this IEnumerable<TSource> source,
Func<TSource, TKey> propertySelector)
{
// TODO: check source and propertySelector not null
// make groups of source items that have the same value for property:
return source.GroupBy(item => propertySelector(item))
// keep only the groups that have more than one element
// it would be a waste to Coun(), just stop after counting more than one
.Where(group => group.Skip(1).Any());
}
这将为您提供具有所选属性重复值的所有源项的组。
在你的情况下:
var itemsWithDuplicateValues = mySourceItems.GetDuplicates(item => item.Value);
这将为您提供所有具有 item.Value 重复值的源项目,按相同的 item.Value 分组
现在您有时间了解为什么要保留 ID 为 444 而不是 111 的项目,您可以编写一个函数,该函数接受一组重复项并返回您要删除的元素。
static IEnumerable<TSource> SelectItemsIWantToRemove<TSource>(
IEnumerable<TSource> source)
{
// TODO: check source not null
// select the items that you want to remove:
foreach (var item in source)
{
if (I want to remove this item)
yield return item;
}
// TODO: make sure there is always one item that you want to keep
// or decide what to do if there isn't any item that you want to keep
}
现在您已经有了一个选择要删除的项目的函数,很容易创建一个 LINQ,该 LINQ 将从您的重复序列中选择要删除的项目:
static IEnumerable<TSource> WhereIWantToRemove<TSource>(
this IEnumerable<IGrouping<TSource>> duplicateGroups)
{
foreach (var group in duplicateGroups)
{
foreach (var sourceItem in group.WhereIWantToRemove())
{
yield return sourceItem;
}
}
}
您也可以为此使用SelectMany。
现在把所有东西放在一起:
static IEnumerable<TSource> WhereIWantToRemove<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> propertySelector)
{
return source.GetDuplicates(propertySelector)
.WhereIWantToRemove();
}
用法:
var itemsToRemove = mySourceItems.WhereIWantToRemove(item => item.Value);
您可以看到我选择创建几个相当小且易于理解的扩展函数。当然,您可以将它们全部放在一个大的 LINQ 语句中。但是,我不确定您是否可以说服您的项目负责人,这将使您的代码具有更好的可读性、可测试性、可维护性和可重用性。所以我的建议是坚持使用小的扩展功能。