与Linq叠加/加入两个集合
我有以下情形:与Linq叠加/加入两个集合
列表1有20个TItem类型的项目,列表2有5个相同类型的项目。清单1已经包含清单2中的项目,但处于不同的状态。我想用列表2中的项目覆盖列表1中的5个项目。
我认为一个联接可能工作,但我想覆盖列表1中的项目,而不是将它们连接在一起并具有重复项目。
有是可用于发现在列表1覆盖哪些项目关键是int类型的唯一密钥
你可以使用内置的LINQ .Except()但它想要一个IEqualityComparer,因此使用.Except()的a fluid version来代替。
假设与的整数键的对象作为你指示:
public class Item
{
public int Key { get; set; }
public int Value { get; set; }
public override string ToString()
{
return String.Format("{{{0}:{1}}}", Key, Value);
}
}
对象的原始列表可以与被改变的一个如下被合并:
IEnumerable<Item> original = new[] { 1, 2, 3, 4, 5 }.Select(x => new Item
{
Key = x,
Value = x
});
IEnumerable<Item> changed = new[] { 2, 3, 5 }.Select(x => new Item
{
Key = x,
Value = x * x
});
IEnumerable<Item> result = original.Except(changed, x => x.Key).Concat(changed);
result.ForEach(Console.WriteLine);
输出:
{1:1}
{4:4}
{2:4}
{3:9}
{5:25}
LINQ不用于进行实际的修改底层数据源;这完全是一种查询语言。当然,你可以在List2
上从List1
做一个外连接,如果它不是null,那么选择List2
的实体,如果它是的实体,但是这会给你一个IEnumerable<>
的结果;它不会真正修改集合。您可以对结果执行ToList()
并将其分配给List1
,但这会改变引用;我不知道这是否会影响您的其他应用程序。
考虑您的问题从字面上看,在你想如果存在的话,以取代List1
与那些从List2
的项目,那么你就必须是手工做的for
遍历List1
,检查相应的存在输入List2
,并用List2
的索引替换List1
。
正如Adam所说,LINQ是关于查询的。但是,您可以使用Enumerable.Union
以正确的方式创建新的集合。您需要创建一个合适的IEqualityComparer
- 如果拥有UnionBy
将会很愉快。 (另外一个为MoreLINQ也许?)
基本上是:
var list3 = list2.Union(list1, keyComparer);
凡keyComparer
将是一个实现这两个键进行比较。 MiscUtil包含一个ProjectionEqualityComparer
这将使这个稍微容易一些。
或者,您可以连接后使用DistinctBy
从MoreLINQ:
var list3 = list2.Concat(list1).DistinctBy(item => item.Key);
下面是与群组加入一个解决方案。
List<string> source = new List<string>() { "1", "22", "333" };
List<string> modifications = new List<string>() { "4", "555"};
//alternate implementation
//List<string> result = source.GroupJoin(
// modifications,
// s => s.Length,
// m => m.Length,
// (s, g) => g.Any() ? g.First() : s
//).ToList();
List<string> result =
(
from s in source
join m in modifications
on s.Length equals m.Length into g
select g.Any() ? g.First() : s
).ToList();
foreach (string s in result)
Console.WriteLine(s);
嗯,怎么样一个可重复使用的扩展方法,而我在这:
public static IEnumerable<T> UnionBy<T, U>
(
this IEnumerable<T> source,
IEnumerable<T> otherSource,
Func<T, U> selector
)
{
return source.GroupJoin(
otherSource,
selector,
selector,
(s, g) => g.Any() ? g.First() : s
);
}
这是由叫做:
List<string> result = source
.UnionBy(modifications, s => s.Length)
.ToList();