C# 如何使用Linq删除基于一个相同值和一个不同值的重复项?
我有一节课C# 如何使用Linq删除基于一个相同值和一个不同值的重复项?,c#,.net,linq,.net-core,C#,.net,Linq,.net Core,我有一节课 class Foo{ string valueOne; string valueTwo; } 我在一个列表中有多个Foo对象。这些对象已经是不同的。但是,如果有另一个对象具有相等的valueOne和valueTwo==null,则我还希望删除对象。保证在valueOne中始终只有一个具有相同值的最大其他“副本”。可以有一个或多个对象具有相同的值one,但值2中的值不同 例如: 在删除具有空值的重复项后,我应该: foo1: valueOne = "Equal
class Foo{
string valueOne;
string valueTwo;
}
我在一个列表中有多个Foo对象。这些对象已经是不同的。但是,如果有另一个对象具有相等的valueOne和valueTwo==null,则我还希望删除对象。保证在valueOne中始终只有一个具有相同值的最大其他“副本”。可以有一个或多个对象具有相同的值one,但值2中的值不同
例如:
在删除具有空值的重复项后,我应该:
foo1:
valueOne = "Equal Value"
valueTwo = "Different"
foo2:
valueOne = "Equal Value"
valueTwo = "Different value"
foo4:
valueOne = "SomeOther Value"
valueTwo = "whatever"
foo5
valueOne = "I have null value, but should still be in list"
valueTwo = null
因此,基本上:一个Foo对象可以留在valueTwo==null的列表中,前提是没有另一个对象具有相同的valueOne
我使用嵌套循环遍历列表,存储重复项的索引,然后在索引上循环,并在列表上使用RemoveAt(index),从而使其工作。然而,这确实是一段又长又难看的代码。有没有办法用Linq来实现这一点?我是C#and Linq的新手,希望这能奏效
谢谢你的帮助
编辑:
为了让它更清楚,我已经在名单上打电话给GroupBy,让它与众不同
编辑2:
该死,我解释得不清楚。可以有一个或多个对象具有相同的值one,但值2中的值不同。不能保证valueOne中始终只有一个具有相同值的最大其他“副本”
虽然可以保证,对于每个具有不同valueOne的Foo对象,只有一个其他Foo对象具有相同的valueOne,但null作为valueTwo。如果这有意义的话..听起来您可能希望您的Foo类实现
IEquatable
,添加您的自定义比较逻辑,然后您可以根据需要在其上使用.Distinct。你可以找到更多关于它的信息
更新:
是使用自定义IEquatable的实现。如果我在您的边缘案例中遗漏了任何内容,您应该能够调整逻辑以满足您的需要。听起来您可能希望您的Foo类实现
IEquatable
,添加自定义比较逻辑,然后您可以使用.Distinct,如您所愿。你可以找到更多关于它的信息
更新:
是使用自定义IEquatable的实现。如果我在您的边缘案例中遗漏了任何内容,您应该能够调整逻辑以满足您的需要。自定义比较器本身无法工作。但使用分组方式的意愿不同。从将按值进行比较的比较器开始:
class FooCompare : IEqualityComparer<Foo>
{
public bool Equals([AllowNull] Foo x, [AllowNull] Foo y)
{
if (null == x && null == y)
return true;
if (null == x || null == y)
return false;
return x.ValueOne == y.ValueOne && x.ValueTwo == y.ValueTwo;
}
public int GetHashCode([DisallowNull] Foo obj)
{
return HashCode.Combine(obj.ValueOne, obj.ValueTwo);
}
}
还包括无法工作的原始GroupBy。自定义比较器本身无法工作。但使用分组方式的意愿不同。从将按值进行比较的比较器开始:
class FooCompare : IEqualityComparer<Foo>
{
public bool Equals([AllowNull] Foo x, [AllowNull] Foo y)
{
if (null == x && null == y)
return true;
if (null == x || null == y)
return false;
return x.ValueOne == y.ValueOne && x.ValueTwo == y.ValueTwo;
}
public int GetHashCode([DisallowNull] Foo obj)
{
return HashCode.Combine(obj.ValueOne, obj.ValueTwo);
}
}
还包括无法使用的原始GroupBy。尝试以下操作:List foos=new List(){foo1,foo2,foo3,foo4};List results=foos.GroupBy(x=>x.valueOne)。选择(x=>x.OrderByDescending(y=>y.valueTwo)。First()).ToList();如果
valueOne
-s相等,但valueTwo
-s都不是null
,该怎么办。这两个项目都应该在结果集合中吗?我个人喜欢@StevenAckley提出的解决方案。它非常干净和简单,因为当您实现IEqualityComparer
时,您只能关注集合中的两个项目,即正在比较的项,框架为您执行所有其他工作。@StevenAckley如何确保Foo.ValueTwo==null是使用自定义比较时由distinct删除的项?请尝试以下操作:List foos=new List(){foo1,foo2,foo3,foo4};List results=foos.GroupBy(x=>x.valueOne)。选择(x=>x.OrderByDescending(y=>y.valueTwo)。First()).ToList();如果valueOne
-s相等,但valueTwo
-s都不是null
,该怎么办。这两个项目都应该在结果集合中吗?我个人喜欢@StevenAckley提出的解决方案。它非常干净和简单,因为当您实现IEqualityComparer
时,您只能关注集合中的两个项目,即正在进行比较的项目,框架为您完成所有其他工作。@StevenAckley如何确保Foo.ValueTwo==null是在使用自定义比较时由distinct删除的项目?我只是不理解如何实现逻辑,在比较时删除具有null值的项目。我试过StevenAckley的建议,我猜是相同的(使用自定义比较器),但我无法理解比较的逻辑..明白了。我想我现在明白了逻辑,但我想核实其中一个案例。如果valueOne相同而valueTwo不同,那么这些是不同的还是相同的?基本上,你是在比较valueOne还是空值two是一个特例?它们被认为是不同的。Foo(“val1”,“something”)和Foo(“val1”,“somethingElse”)被认为是不同的,应该留在列表中。但是,如果还有Foo(“val1”,null),那么应该删除该对象。如果说得通的话,好吧,酷。我已经用一个工作示例更新了我的答案。这是否依赖于始终存在哈希冲突?如果我给它一个实际工作的GetHashCode实现,它对我来说是不起作用的。另外,如果您将此逻辑放在IEqualityComparer中而不是IEquatable中,则会更好。您已经将专门的逻辑绑定到类型的等式中。我只是不明白如何实现逻辑,在比较时删除具有空值的逻辑。我试过StevenAckley的建议,我猜是相同的(使用自定义比较器),但我无法理解比较的逻辑..明白了。我想我现在明白了逻辑,但我想核实其中一个案例。如果valueOne相同而valueTwo不同,那么这些是不同的还是相同的?基本上,你是在比较valueOne还是空值two是一个特例?它们被认为是不同的。Foo(“val1”,“某物”)
static void Main(string[] _)
{
var data = new Foo[] {
new Foo { ValueOne = "Equal Value", ValueTwo = null },
new Foo { ValueOne = "Equal Value", ValueTwo = "Different" },
new Foo { ValueOne = "Equal Value", ValueTwo = "not same" },
new Foo { ValueOne = "SomeOtherValue", ValueTwo = "Different" },
new Foo { ValueOne = "SomeOtherValue", ValueTwo = null },
new Foo { ValueOne = "I have null value, but should still be in list",
ValueTwo = null },
};
var check = new Foo[] {
new Foo { ValueOne = "Equal Value", ValueTwo = "Different" },
new Foo { ValueOne = "Equal Value", ValueTwo = "not same" },
new Foo { ValueOne = "SomeOtherValue", ValueTwo = "Different" },
new Foo { ValueOne = "I have null value, but should still be in list",
ValueTwo = null },
}.OrderBy(x => x.ValueOne);
var compare = new FooCompare();
var result2 = data.GroupBy(x => x.ValueOne)
.SelectMany(g =>
{
var d = g.Distinct(compare);
var nonNull = d.Where(x => x.ValueTwo != null);
if (nonNull.Any())
return nonNull;
return d;
})
.OrderBy(x => x.ValueOne)
.ToArray();
if (!Enumerable.SequenceEqual(check, result2, new FooCompare()))
Console.WriteLine("Failed");
else
Console.WriteLine("Success");
// this one will not work.
var result = data.GroupBy(x => x.ValueOne)
.Select(g => g.OrderByDescending(y => y.ValueTwo).First())
.ToArray();
if (!Enumerable.SequenceEqual(check, result, new FooCompare()))
Console.WriteLine("Failed");
else
Console.WriteLine("Success");
}