我有一个对象列表。这些物体具有例如“值”。
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);
我想说的是:
lst.PartialDistinct(x => x.Value == "A")
这应仅与谓词不同,并且在打印生成的IEnumerable的“值”时,结果应为:
A
B
B
我已经找到了DistinctBy的解决方案,可以定义一个Key-Selector。但结果当然是:
A
B
Cyral的第一个答案完成了这项工作。所以我接受了它。但Scott的回答实际上是一个PartialDistinct()方法,看起来它解决了我所有的问题。
好吧,以为它是用斯科特的解决方案解决的,但事实并非如此。也许我在进行单元测试时犯了错误......或者我不知道。问题是:
if(seen.Add(item))
这不会过滤掉值为“A”的其他对象。我认为这是因为它在放入hashset时依赖于引用相等性。
我最终得到了以下解决方案:
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)));
}
答案 0 :(得分:4)
您可以按Value
进行分组,并使用SelectMany
执行'条件展平',即只从“A”组中获取一个元素,并从其余部分中获取所有元素基团:
var result = lst.GroupBy(x => x.Value)
.SelectMany(g => g.Key == "A" ? g.Take(1) : g);
答案 1 :(得分:3)
尝试找到与您的值匹配的元素,获取其中的第一个元素,然后将其与所有与您的值不匹配的元素加入。
var match = "A";
var result = lst
.Where(x => x.Value == match)
.Take(1)
.Concat(lst
.Where(x => x.Value != match))
.Select(x => x.Value);
答案 2 :(得分:3)
如果您希望在TestNode
上Value == A
加上Value != A
加上正常结果集,public static class ExtensionMethods
{
public static IEnumerable<T> PartialDistinct<T>(this IEnumerable<T> source, Func<T, bool> filter)
{
return PartialDistinct(source, filter, EqualityComparer<T>.Default);
}
public static IEnumerable<T> PartialDistinct<T>(this IEnumerable<T> source, Func<T, bool> filter, IEqualityComparer<T> comparer)
{
HashSet<T> seen = new HashSet<T>(comparer);
foreach (var item in source)
{
if (filter(item))
{
if (seen.Add(item))
{
yield return item;
}
}
else
{
yield return item;
}
}
}
只执行该过程,并将其包含在扩展方法中。
{{1}}
答案 3 :(得分:0)
创建两个不同的列表并连接它们也是一种方式。
var answer = lst.Where(val=>val == "A").Select(note=>note.Value).Distinct().Concat(
lst.Where(node => node.Value == "B").Select(node => node.Value));