I have a list of objects. These objects have a property e.g. "Value".
var lst = new List<TestNode>();
var c1 = new TestNode()
{
Value = "A",
};
lst.Add(c1);
var c2 = new TestNode()
{
Value = "A",
};
lst.Add(c2);
var c3 = new TestNode()
{
Value = "B",
};
lst.Add(c3);
var c4 = new TestNode()
{
Value = "B",
};
lst.Add(c4);
I would like to say something like:
lst.PartialDistinct(x => x.Value == "A")
This should only be distinct by predicate and when printing the "Value"s of the resulting IEnumerable the result should be:
A
B
B
I already found solutions for DistinctBy where it's possible to define a Key-Selector. But the result is then of course:
A
B
Cyral's first answer did the job. So I accepted it. But Scott's answer is really a PartialDistinct() Method as asked and looks like it solves all my problems.
Ok, thought it's solved with Scott's solution but it's not. Maybe I made a mistake while unit testing... or I don't know. The problem is:
if(seen.Add(item))
This does not filter out other objects with value "A".I think this is because it relies on referential equality when putting into hashset.
I ended up with following solution:
public static IEnumerable<T> PartialDistinct<T>(this IEnumerable<T> source Func<T, bool> predicate)
{
return source
.Where(predicate)
.Take(1)
.Concat(source.Where(x => !predicate(x)));
}
You can group by Value and perform 'conditional flattening' using SelectMany, i.e. take only one element from 'A' groups and all elements from the rest of the groups:
var result = lst.GroupBy(x => x.Value)
.SelectMany(g => g.Key == "A" ? g.Take(1) : g);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With