【问题标题】:Linq query to find a match where nested list contains sequence [duplicate]Linq查询以查找嵌套列表包含序列的匹配项[重复]
【发布时间】:2018-03-13 15:03:49
【问题描述】:

鉴于这两个对象:

public class Foo{
   public string Result {get;set;}
   public List<Bar> Bars {get;set;}
}

public class Bar{
   public string Left {get;set;}
   public string Right {get;set;}
}

这些实例如下所示:

List<Foo> myFoos = new List<Foo>()
        {
    new Foo { Bars = new List<Bar>
        {
            new Bar { Left = "myLeft1", Right = "myValue1"},
            new Bar { Left = "myLeft2", Right = "myValue2"}
        },
        Result = "TheWinningResult"},
    new Foo { Bars = new List<Bar>
        {
            new Bar { Left = "myLeft2", Right = "myValue2"},
            new Bar { Left = "myLeft3", Right = "myValue3"}
        },
        Result = "TheLosingResult"},
    new Foo{ Bars = new List<Bar>
        {
            new Bar { Left = "myLeft1", Right = "myValue1"},
            new Bar { Left = "myLeft2", Right = "myValue2"},
            new Bar { Left = "myLeft3", Right = "myValue3"}
        },
        Result = "TheOtherLosingResult"},
};

List<Bar> bars = new List<Bar>()
{
     new Bar{  Left = "myLeft1", Right = "myValue1" },
     new Bar{  Left = "myLeft2", Right = "myValue2" }
};

我正在尝试查找 FirstOrDefault() Foo 其中 Foo.Barsbars 完全匹配

在这种情况下,我试图返回Foo,而Result 是“TheWinningResult”

我尝试了以下方法:

Foo foo =  myFoos.Where(t => t.Bars.All(t2 => bars.Contains(t2))).FirstOrDefault();

Foo foo = myFoos.Where(t => bars.All(r => t.Bars.Contains(r))).FirstOrDefault();     

Foo foo =   myFoos.FirstOrDefault(t => t.Bars.Any(r => bars.All(ru => ru.Left == r.Left && ru.Right == r.Right)));

知道我哪里出错了吗?

更新

我忘了说,Foo 中的Bars 的顺序应该不重要。

【问题讨论】:

  • myFoos.FirstOrDefault(x =&gt; x.Bars.SequenceEqual(bars)); msdn.microsoft.com/en-us/library/bb348567(v=vs.110).aspx
  • @RandRandom - 对我不起作用,谢谢。
  • 你确实覆盖了Equals - 假设?
  • @RandRandom - 不。我没有。
  • 我没有对自己投反对票,但该示例在不进行更改的情况下无法编译。 Foo 缺少对 Result 的定义,并且大括号和初始化 Bar 存在其他问题。

标签: c# linq


【解决方案1】:

问题在于 contains 如何比较对象。默认情况下,比较是通过引用相等来完成的。在这里,您需要不同的行为 - 按内容比较平等。这样做覆盖EqualsGetHashCodeBar

public override bool Equals(object obj)
{
    var other = obj as Bar;
    if (obj == null)
        return false;
    return other.Left == Left && other.Right == Right;
}

public override int GetHashCode()
{
    unchecked
    {
        int hash = 17;
        hash = hash * 23 + Left.GetHashCode();
        hash = hash * 23 + Right.GetHashCode();
        return hash;
    }
}

然后可以通过以下方式检索正确的对象:

var result = myFoos.Where(item => bars.Count == item.Bars.Count && 
                                  !bars.Except(item.Bars).Any());

或者如果使用SequenceEqual:

var result = myFoos.Where(item => bars.SequenceEqual(item.Bars));

另一种方法是实现IEqualityComparer&lt;Bar&gt; 并调用匹配的Contains 重载:

var result = myFoos.Where(t => t.Bars.All(t2 => bars.Contains(t2, new BarEqualityComparer())));

至于您的第三次尝试,问题在于 AllAny 是相反的:您希望 foo 中的所有条都与 bars 列表中的任何项目匹配:

Foo foo = myFoos.FirstOrDefault(t => t.Bars.All(r => bars.Any(ru => ru.Left == r.Left && ru.Right == r.Right)));

对于 GetHashCode 的覆盖是什么,您可以阅读以下两个:

  1. Object.GetHashCode
  2. Why is it important to override GetHashCode when Equals method is overridden?

【讨论】:

  • 懒惰自己,也许可以解释一下为什么他的第三次尝试失败了Foo foo = myFoos.FirstOrDefault(t =&gt; t.Bars.Any(r =&gt; bars.All(ru =&gt; ru.Left == r.Left &amp;&amp; ru.Right == r.Right)));
  • @RandRandom - 更新:)
  • @GiladGreen - 非常感谢!你介意简单解释一下 GetHashCode() 的覆盖是什么吗?
  • @Darren - 查看更新
猜你喜欢
  • 2021-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 2017-11-29
相关资源
最近更新 更多