简体   繁体   English

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

[英]Compare sublist of a list for objects that change, in Linq

I have a List of objects that has a sublist of strings and these structures can change between days and I'm looking to compare them to see if a change was made. 我有一个对象列表,该对象列表包含一个字符串子列表,并且这些结构在几天之间可能会发生变化,因此我希望将它们进行比较以查看是否进行了更改。

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

The ID field is the same between versions of the list and Ingredients is just a list of strings . 列表的版本之间ID字段相同,而Ingredients只是字符串列表。

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

I'm trying to find all Recipe s that have ingredient changes between days. 我正在尝试查找所有在几天之间成分都有变化的Recipe I've been able to come up with a Linq statement to find new Recipe s that are in list2 but not list1 by something like this 我已经能够提出一个Linq语句,以通过类似这样的方式找到list2而不是list1中的新Recipe

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

But, I haven't figured out yet how to select only Recipe s that have had Ingredient changes between lists. 但是,我还没有弄清楚如何仅选择在列表之间具有Ingredient更改的Recipe

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

How can I get a list of objects that have had changes in a sublist of strings? 如何获得在字符串子列表中已更改的对象的列表?

This code will get you pairs of every non matching recepies of the same ID. 此代码将使您获得具有相同ID的每个不匹配收据的对。 You have to sort the ingredients lists for SequenceEqual to work though. 您必须对成分列表进行排序以使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 };

Sure, you can do that.Get MoreLINQ first of all (it can be done without it, however it's slightly more inefficient, ask me if you want it). 当然,您可以做到。首先获取MoreLINQ (可以在没有它的情况下完成,但是效率稍低,请问我是否要这样做)。 However, before that we need to add a better enumerable IEqualityComparer : 但是,在此之前,我们需要添加更好的可枚举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;
    }
}

After that it's as simple as this: 之后,就这么简单:

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

If you're going to be using this around your code, I wouldn't instantiate a new EnumerableComparer all the time, as they're all the same. 如果您打算在代码中使用它,我不会一直实例化一个新的EnumerableComparer,因为它们都是一样的。 Use the same instance for each type. 每种类型使用相同的实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM