繁体   English   中英

通过LINQ比较两个列表

[英]Compare Two Lists Via LINQ

我有两个列表会说ListA和ListB。 我需要遍历ListB并将ID与ListA进行比较。 如果存在匹配项,那么我需要从ListB中删除该项目,并将其替换为ListA中匹配的项目/对象。

我一直在看这篇文章。 我也看过相交。 但是我真的不确定如何使它与Linq一起使用。

这是我的代码:

ListB是在其他位置生成并传入的查询

var itemsForListA = Context.Set<Item>().AsQueryable();
var ListA = from i in itemsForListA 
            where i.ReplacementItemID != null
                  && (i.ItemStatus == "DISC" || i.ItemStatus == "ACT" 
                  && i.StoreID == null)
            select i;

foreach (var i in ListB)
{
    ListB = ListA.Where(x => x.Id == ListA.Id);
}

我以为我可以做这样的事情。 我是否首先必须在ListB中找到ID并将其删除,然后将新ID附加到ListA到B?

我认为您可以在linq中使用左联接,如下所示。

var list = from lb in ListB
    join la in ListA
        on lb.Id equals la.Id into ListC
    from lc in ListC.DefaultIfEmpty()
    select lc ?? lb;

它不会删除和替换项目,但是会产生相同的结果,您可以将其重新分配给ListB

使用IEqualityComparer使用内置的Enumerable.Except()方法。

类进行比较

public class Item
{
  public int Id { get; set; }
}

比较器

public class ItemIdComparer<Item>
{
  public bool Equals(Item left, Item right)
  {
    return left.Id == right.Id;
  }
  public int GetHashCode(Item item)
  {
    return item.Id.GetHashCode();
  }
}

用法

var all = new List<Item>();
var existing = new List<Item>();

var nonExisting = all.Except(existing, new ItemIdComparer())

我无法完全测试...但是应该非常接近。

您可以执行以下操作:

var list = listB.Join(listA, x => x.Id, y => y.Id, (x, y) => y).ToList();

list.AddRange(listB.Where(b => listA.Any(c => c.Id != b.Id)).ToList());
  1. 首先,我将listA与listB进行比较,并从listA中选择具有相同ID的对象。
  2. 到所选对象中,我将其添加到listB中,这些元素与listA没有公共ID。

我不确定您的模型如何,因此我创建了自己的模型:

public class Person
{
    public int Id { get; set; }
    public string FullName { get; set; }
    public byte Age { get; set; }
}

创建相等比较器:

public class PersonComaparer : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        if (x == null && y == null)
            return true;

        if ((x == null && y != null)
            || (x != null && y == null))
            return false;

        return x.Id == y.Id;
    }

    public int GetHashCode(Person obj)
    {
        if (obj == null)
            return 0;

        return obj.Id.GetHashCode();
    }
}

然后使用它们来比较列表:

List<Person> ListA = new List<Person>
{
    new Person { Id = 1, FullName = "Someone" }
};

List<Person> ListB = new List<Person>
{
    new Person { Id = 1 },
    new Person { Id = 2 }
};

PersonComaparer comparer = new PersonComaparer();
ListB = ListA
    .Intersect(ListB, comparer)
    .Union(ListB, comparer)
    .ToList();

结果将是:

Id  |   Full name
1       Someone
2       null

我将下面的答案与使用10,000个项目的Bapaiah Malasani的join解决方案进行了比较。 我的解决方案持续花费了六秒钟或更长时间。 他的持续时间不超过10毫秒。 哎哟。 我必须回头查看一下我编写的大量代码。


您应该使用IEqualityComparer<Item>吗? 我会的,因为您可能会有很多这样的代码。 编写一次并永久使用:

public class ItemComparer: IEqualityComparer<Item>
{
    public bool Equals(Item i1, Item i2)
    {
        if(i1 == null && i2 == null) return true;
        if(i1 == null ^ i2 ==null) return false;
        return(i1 == i2 || i1.Id == i2.Id);
    }

    public int GetHashCode(Item item)
    {
        return item != null ? item.Id.GetHashcode() : 0;
    }
}

然后,您可以将整个内容包装在一个易于阅读的函数中。 使用一系列Linq语句,可能不清楚您的意图是什么。 但是具有明确名称的函数会有所帮助:

IEnumerable<T> ReplaceMatchingItems<T>(IEnumerable<T> discardFrom,
    IEnumerable<T> replaceWith,
    IEqualityComparer<T> comparer = null)
    {
        //prevent multiple enumerations
        var discardFromArray = discardFrom as T[] ?? discardFrom.ToArray();
        var replacements = replaceWith.Where(item => discardFromArray.Contains(item, comparer)).ToArray();
        var newList = discardFromArray.Except(replacements, comparer).ToList();
        newList.AddRange(replacements);
        return newList;
    }

现在,您想要的原始函数如下所示:

var listWithReplacements = ReplaceMatchingItems(ListB, ListA, new ItemComparer());

IEqualityComparer ,它看起来像是更多代码,但是IEqualityComparer可以为您节省大量时间。 而且,当有人看到诸如ReplaceMatchingItems类的函数调用时,他们更有可能了解代码在做什么,而不仅仅是看一堆Linq查询。

暂无
暂无

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

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