You forgot to say why you want to keep item 444 and not item 111 instead of the other way around.
LINQ is developed to query data. LINQ will never change the original source sequence.
You can use LINQ to query the items that you want to remove, and then use a foreach to remove the items one by one.
To query the items with duplicates is easy. If you need this function more often, consider creating an extension function for this:
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());
}
This will give you groups of all source items that have duplicate values for the selected property.
In your case:
var itemsWithDuplicateValues = mySourceItems.GetDuplicates(item => item.Value);
This will give you all your source items that have duplicate values for item.Value, grouped by same item.Value
Now that you've got time to find out why you want to keep item with Id 444 and not 111, you can write a function that takes a group of duplicates and returns the elements that you want to remove.
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
}
Now that you've got a function that selects the items that you want to remove it is easy to create a LINQ that will select from your sequence of duplicates the item that you want to remove:
static IEnumerable<TSource> WhereIWantToRemove<TSource>(
this IEnumerable<IGrouping<TSource>> duplicateGroups)
{
foreach (var group in duplicateGroups)
{
foreach (var sourceItem in group.WhereIWantToRemove())
{
yield return sourceItem;
}
}
}
You could also use a SelectMany
for this.
Now put everything together:
static IEnumerable<TSource> WhereIWantToRemove<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> propertySelector)
{
return source.GetDuplicates(propertySelector)
.WhereIWantToRemove();
}
Usage:
var itemsToRemove = mySourceItems.WhereIWantToRemove(item => item.Value);
You can see that I chose to create several fairly small and easy to understand extension functions. Of course you can put them all together in one big LINQ statement. However, I'm not sure if you can convince your project leader that this would make your code better readable, testable, maintainable and re-usable. So my advice would be to stick to the small extension functions.