C# 部分相异Linq
我有一个物品清单。这些对象具有属性,例如“值” 这只能通过谓词区分,并且在打印结果IEnumerable的“值”时,结果应为:C# 部分相异Linq,c#,linq,C#,Linq,我有一个物品清单。这些对象具有属性,例如“值” 这只能通过谓词区分,并且在打印结果IEnumerable的“值”时,结果应为: A B B 我已经找到了通过定义键选择器来区分的解决方案。但结果当然是: A B Cyral的第一个回答起了作用。所以我接受了。但是Scott的答案实际上是一个PartialDistinct()方法,看起来它解决了我所有的问题 好吧,我以为斯科特的解决方案解决了,但事实并非如此。也许我在单元测试时犯了一个错误。。。或者我不知道。问题是: if(seen.Add(it
A
B
B
我已经找到了通过定义键选择器来区分的解决方案。但结果当然是:
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)));
}
public static IEnumerable PartialDistinct(此IEnumerable源函数谓词)
{
返回源
.Where(谓词)
.采取(1)
.Concat(source.Where(x=>!谓词(x));
}
尝试查找与您的值匹配的元素,取其中的第一个元素,然后将其与所有与您的值不匹配的元素合并
var match = "A";
var result = lst
.Where(x => x.Value == match)
.Take(1)
.Concat(lst
.Where(x => x.Value != match))
.Select(x => x.Value);
如果要在
TestNode
上进行区分,其中Value==A
加上正常结果集,其中Value!=一个
只需执行这个精确的过程,并将其封装到一个扩展方法中
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;
}
}
}
公共静态类扩展方法
{
公共静态IEnumerable PartialDistinct(此IEnumerable源,Func筛选器)
{
返回PartialDistinct(源、筛选器、EqualityComparer.Default);
}
公共静态IEnumerable PartialDistinct(此IEnumerable源、Func筛选器、IEqualityComparer比较器)
{
HashSet seen=新的HashSet(比较器);
foreach(源中的var项)
{
if(过滤器(项目))
{
如果(见添加(项目))
{
收益回报项目;
}
}
其他的
{
收益回报项目;
}
}
}
创建两个不同的列表并连接它们也是一种方法
var answer = lst.Where(val=>val == "A").Select(note=>note.Value).Distinct().Concat(
lst.Where(node => node.Value == "B").Select(node => node.Value));
您可以按
Value
分组,并使用SelectMany
执行“条件展平”,即只从“A”组中选取一个元素,从其余组中选取所有元素:
var result = lst.GroupBy(x => x.Value)
.SelectMany(g => g.Key == "A" ? g.Take(1) : g);
是否有
TestNode
其他属性?这些属性在单个剩余对象上的值应该是什么?是否要在Value
上执行distinct,或在TestNode
上执行distinct,其中Value==a
加上正常结果集,其中Value!=a
?取(1)和distinct()如果TestNode
在GetHashCode
中不只过滤Value
和Equals
,则会有非常不同的行为(我没有-1,我认为你的答案是好的。OP在问题中不清楚他是否想要一个不同的值,所以这两种方法都很好)@ScottChamberlain噢,我明白你的意思了,我写这篇文章时错误地认为我是在对值而不是对象调用Distinct()。第二个版本可能更好solution@KeithNicholas你是对的,我更新了答案,只使用了第二个版本。第二个解决方案不起作用。如果(seen.Add(item))没有过滤出带有“A”的对象。好的,您需要传入一个比较器来检查值
,或者重写GetHashCode
和等于
来比较属性值
,而不是默认的比较。
var answer = lst.Where(val=>val == "A").Select(note=>note.Value).Distinct().Concat(
lst.Where(node => node.Value == "B").Select(node => node.Value));
var result = lst.GroupBy(x => x.Value)
.SelectMany(g => g.Key == "A" ? g.Take(1) : g);