Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用Linq删除基于一个相同值和一个不同值的重复项?_C#_.net_Linq_.net Core - Fatal编程技术网

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");
    }