.net 使用LINQ混合2个阵列
我需要将两个数组(.net 使用LINQ混合2个阵列,.net,linq,.net,Linq,我需要将两个数组(List)相交,只保留不同的元素,并将一个数组的元素与另一个数组的元素混合,如下所示: A1 B1 C1 D1 W2 X2 Y2 Z2 => A1 W2 B1 X2 C1 Y2 D1 Z2 A1 B1 A1 D1 W2 X2 Y2 Z2 => A1 W2 B1 X2 Y2 D1 Z2 // repeating A1 A1 B1 A1 D1 Z2 X2 Y2 Z2 => A1 Z2 B1 X2
List
)相交,只保留不同的元素,并将一个数组的元素与另一个数组的元素混合,如下所示:
A1 B1 C1 D1
W2 X2 Y2 Z2
=> A1 W2 B1 X2 C1 Y2 D1 Z2
A1 B1 A1 D1
W2 X2 Y2 Z2
=> A1 W2 B1 X2 Y2 D1 Z2 // repeating A1
A1 B1 A1 D1
Z2 X2 Y2 Z2
=> A1 Z2 B1 X2 Y2 D1 // repeating A1, Z2
A1 B1 C1 D1 E1
Z2 X2 Y2
=> A1 Z2 B1 X2 C1 Y2 D1 E1
最佳的LINQ查询是什么 (顺便说一句,List
不是数组。)
如果您使用.NET 4,并且假设数组长度相同,我认为这将满足您的需要:
var query = first.Zip(second, (x, y) => new[] { x, y })
.SelectMany(pair => pair)
.Distinct();
编辑:正如评论中指出的那样,Distinct
的顺序不受保证。然而,我希望它实际上在实践中保持不变。。。考虑到我所建议的其他变化,这些变化只会以积极(微小)的方式影响可观察的结果,我无法想象这会发生变化
Lassespeholt的解决方案处理交织部分。如果您想要绝对有保证的订购,您可以始终自己实施Disrinct,就像我在Edulink中所做的那样:
public static IEnumerable<TSource> OrderPreservingDistinct<TSource>(
this IEnumerable<TSource> source)
{
return source.OrderPreservingDistinct(EqualityComparer<TSource>.Default);
}
public static IEnumerable<TSource> OrderPreservingDistinct<TSource>(
this IEnumerable<TSource> source,
IEqualityComparer<TSource> comparer)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
return OrderPreservingDistinct(source, comparer ??
EqualityComparer<TSource>.Default);
}
private static IEnumerable<TSource> OrderPreservingDistinct<TSource>(
IEnumerable<TSource> source,
IEqualityComparer<TSource> comparer)
{
HashSet<TSource> seenElements = new HashSet<TSource>(comparer);
foreach (TSource item in source)
{
if (seenElements.Add(item))
{
yield return item;
}
}
}
也许不只是使用LINQ,但我认为使用简单且足够快
//List<string> l1 = new List<string>() { "A1", "B1", "C1", "D1" };
List<string> l1 = new List<string>() { "A1", "B1", "A1", "D1" };
//List<string> l2 = new List<string>() { "W2", "X2", "Y2", "Z2" };
List<string> l2 = new List<string>() { "Z2", "X2", "Y2", "Z2" };
List<string> ls = new List<string>();
ls.AddRange(l1);
ls.AddRange(l2);
ls = ls.Distinct().ToList();
//列表l1=新列表(){“A1”、“B1”、“C1”、“D1”};
列表l1=新列表(){“A1”、“B1”、“A1”、“D1”};
//列表l2=新列表(){“W2”、“X2”、“Y2”、“Z2”};
列表l2=新列表(){“Z2”、“X2”、“Y2”、“Z2”};
列表ls=新列表();
ls.AddRange(l1);
ls.AddRange(l2);
ls=ls.Distinct().ToList();
一种交织扩展方法(取代Jon Skeets版本中的Zip
/SelectMany
)。这可能会快一点,如果列表的长度不相等,它会包括最长列表的剩余部分:
public static IEnumerable<T> Interleave<T>(this IEnumerable<T> first, IEnumerable<T> second)
{
var e0 = first.GetEnumerator();
var e1 = second.GetEnumerator();
bool e0HasValue = false;
bool e1HasValue = false;
// Could be made a little faster by not checking both when one is empty
while ((e0HasValue = e0.MoveNext()) | (e1HasValue = e1.MoveNext()))
{
if (e0HasValue)
yield return e0.Current;
if (e1HasValue)
yield return e1.Current;
}
}
当然,这个答案并不能解决Jon Skeet答案评论中描述的关于
Distinct
的不确定性。但它可以与Jon Skeet的保序扩展方法相结合。这看起来不像是正常意义上的交叉点…@Jon Skeet:Edit to'Mix'+添加了不同的数组大小。重申一下,列表
不是数组。我想你是想引用序列的一般概念。@Jon:如果你想的话,就让它成为序列吧。我不认为这对这个话题真的很重要。在我看来,表达的清晰总是非常重要的。了解不同术语的含义并恰当地使用它们是非常值得的。嗯。。。如果我们抑制约束“数组的长度相同”,它会改变一些东西?比如说,如果长度不同,我总是可以用最后一个元素的长度来完成最小的数组…可能值得指出的是,Distinct()之后的顺序是显式未指定的()[解释:)]@塞尔希奥:这变得更加棘手,因为当较短的列表完成时,Zip将停止。@塞尔希奥:不,绝对不是-你应该使用LasseSpeholt的答案,正如我的答案中指定的那样。我认为把它复制到我的答案中没有任何意义。
public static IEnumerable<T> Interleave<T>(this IEnumerable<T> first, IEnumerable<T> second)
{
var e0 = first.GetEnumerator();
var e1 = second.GetEnumerator();
bool e0HasValue = false;
bool e1HasValue = false;
// Could be made a little faster by not checking both when one is empty
while ((e0HasValue = e0.MoveNext()) | (e1HasValue = e1.MoveNext()))
{
if (e0HasValue)
yield return e0.Current;
if (e1HasValue)
yield return e1.Current;
}
}
var result = firstList.Interleave(secondList).Distinct();