Linq查询以查找嵌套列表包含序列的匹配项

时间:2017-10-02 14:12:30

标签: c# linq

鉴于这两个对象:

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.Bars具有完全匹配的bars

在这种情况下,我正在尝试返回FooResult是&#34; TheWinningResult&#34;

我尝试了以下内容:

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

知道我哪里错了吗?

更新

我忘了提及,BarsFoo的顺序无关紧要。

1 个答案:

答案 0 :(得分:4)

问题在于如何比较对象。默认情况下,比较由引用相等性完成。在这里,您需要一种不同的行为 - 按内容比较相等。为此,请覆盖Equals的{​​{1}}和GetHashCode

Bar

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

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<Bar>重载:

Contains

至于你的第三次尝试,问题是var result = myFoos.Where(t => t.Bars.All(t2 => bars.Contains(t2, new BarEqualityComparer()))); All是相反的:你希望foo中的所有条形都匹配{{1}中的任何项目list:

Any

对于 bars覆盖的内容,您可以阅读以下两项内容:

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