通过 LINQ 比较两个列表
Compare Two Lists Via LINQ
我有两个列表,分别是 ListA 和 ListB。我需要遍历 ListB 并将 ID 与 ListA 进行比较。如果有匹配项,那么我需要从 ListB 中删除该项目并将其替换为 ListA 中匹配的 item/object。
我一直在看 THIS 文章。我也看过 Intersect。但我真的不确定如何让它与 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?
您可以按如下方式进行:
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());
- 首先,我将 listA 与 listB 进行比较,并从 listA 中选择具有相同 ID 的对象。
- 我将 listB 中的元素添加到所选对象中,这些元素与 listA 没有共同的 ID。
我认为您可以在 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()
方法。
Class 比较
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())
我无法准确测试...但应该非常接近。
我不确定你的模型长什么样,所以我创建了自己的模型:
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
我将下面的答案与 Bapaiah Malasani 的 join
使用 10,000 个项目的解决方案进行了比较。我的解决方案始终需要 6 秒或更长时间。他的持续时间为 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
会在以后为您节省大量时间。当有人看到像 ReplaceMatchingItems
这样的函数调用时,他们更有可能理解代码在做什么,而不是仅仅查看一堆 Linq 查询。
我有两个列表,分别是 ListA 和 ListB。我需要遍历 ListB 并将 ID 与 ListA 进行比较。如果有匹配项,那么我需要从 ListB 中删除该项目并将其替换为 ListA 中匹配的 item/object。
我一直在看 THIS 文章。我也看过 Intersect。但我真的不确定如何让它与 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?
您可以按如下方式进行:
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());
- 首先,我将 listA 与 listB 进行比较,并从 listA 中选择具有相同 ID 的对象。
- 我将 listB 中的元素添加到所选对象中,这些元素与 listA 没有共同的 ID。
我认为您可以在 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()
方法。
Class 比较
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())
我无法准确测试...但应该非常接近。
我不确定你的模型长什么样,所以我创建了自己的模型:
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
我将下面的答案与 Bapaiah Malasani 的 join
使用 10,000 个项目的解决方案进行了比较。我的解决方案始终需要 6 秒或更长时间。他的持续时间为 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
会在以后为您节省大量时间。当有人看到像 ReplaceMatchingItems
这样的函数调用时,他们更有可能理解代码在做什么,而不是仅仅查看一堆 Linq 查询。