在Linq中比较更改对象的列表的子列表

时间:2013-06-21 21:41:23

标签: c# linq list

我有一个包含字符串子列表的对象列表,这些结构可以在几天之间变化,我希望比较它们以查看是否进行了更改。

public class Recipe
{
    public string ID { get; set; }
    public string Name { get; set; }
    public List<string> Ingredients { get; set; }
} 

ID字段在列表版本之间是相同的,Ingredients只是字符串的列表。

List<Recipe> list1 = GetRecipes("2013-06-20");
List<Recipe> list2 = GetRecipes("2013-06-21");

我正在尝试查找所有Recipe个天数之间的成分变化。我已经能够提出一个Linq语句来查找 list2 中的新Recipe但不是 list1 这样的

var newRecipes = list1.Where(x => !list2.Any(x1 => x1.ID == x.ID))
    .Union(list2.Where(x => !list1.Any(x1 => x1.ID == x.ID)));

但是,我还没有想出如何仅选择列表之间发生Recipe更改的Ingredient

var modifiedRecipes = list1.Where(x => !list2.Any(x1 => x1.ID == x.ID && x1.Ingedients.SequenceEqual(x.Ingedients)))
    .Union(list2.Where(x => !list1.Any(x1 => x1.ID == x.ID && x1.Ingedients.SequenceEqual(x.Ingedients))));

如何获取字符串子列表中已更改的对象列表?

2 个答案:

答案 0 :(得分:3)

此代码将为您提供相同ID的每个非匹配配方的对。您必须对SequenceEqual的成分列表进行排序才能正常工作。

var changed = from older in GetRecipes("2013-06-20")
              join newer in GetRecipes("2013-06-21") on older.ID equals newer.ID
              where !older.Ingredients.SequenceEquals(newer.Ingredients)
              select new { older, newer };

答案 1 :(得分:2)

当然,你可以做到这一点。首先获得MoreLINQ(没有它可以完成,但效率稍低,请问我是否需要它)。但是,在此之前我们需要添加更好的可枚举IEqualityComparer

public class EnumerableComparer<T> : IEqualityComparer<IEnumerable<T>>
{
    public void Equals(IEnumerable<T> x, IEnumerable<T> y)
    {
        return x.SequenceEqual(y);
    }
    public int GetHashCode(IEnumerable<T> obj)
    {
        int x = 31;
        foreach (T element in obj)
        {
            x += 37 * element.GetHashCode();
        }
        return x;
    }
}

之后它就像这样简单:

var modifiedRecipes = list2.ExceptBy(list1, n => n.Ingredients,
    new EnumerableComparer<string>());

如果你要在你的代码周围使用它,我不会一直实例化一个新的EnumerableComparer,因为它们都是一样的。对每种类型使用相同的实例。