我有两组数据行,它们各自是IEnumerable类型。我想将这两个列表连接成一个列表。我知道这是可以做到的。我不想使用循环,注意到两个列表上有Union方法和Join方法。有什么建议吗?
我有两组数据行,它们各自是IEnumerable类型。我想将这两个列表连接成一个列表。我知道这是可以做到的。我不想使用循环,注意到两个列表上有Union方法和Join方法。有什么建议吗?
Union
或 Concat
。请注意,就像 SQL 中的 UNION
关键字一样,Union
操作将确保消除重复项,而 Concat
(与 UNION ALL
类似)只会将第二个列表添加到第一个列表的末尾。IEnumerable<T> first = ...;
IEnumerable<T> second = ...;
IEnumerable<T> combined = first.Concat(second);
或者
IEnumerable<T> combined = first.Union(second);
Select
到一个共同的类型中。例如:IEnumerable<TOne> first = ...;
IEnumerable<TTwo> second = ...;
IEnumerable<T> combined = first.Select(f => ConvertToT(f)).Concat(
second.Select(s => ConvertToT(s)));
ConvertToT(TOne f)
和ConvertToT(TTwo s)
分别表示一种将TOne
(和TTwo
)的实例转换为T
实例的操作。
Union
有一个重载,允许您指定一个IEqualityComparer
。 - Adam Robinson我最近遇到了一个类似的情况,需要将多个序列连接起来。
我自然地在Google/StackOverflow上搜索现有的解决方案,但是没有找到不评估枚举的任何内容,例如将其转换为数组,然后使用Array.Copy()
等,因此我编写了一个扩展和静态实用程序方法,称为ConcatMultiple
。
希望这可以帮助需要执行相同操作的任何人。
/// <summary>
/// Concatenates multiple sequences
/// </summary>
/// <typeparam name="TSource">The type of the elements of the input sequences.</typeparam>
/// <param name="first">The first sequence to concatenate.</param>
/// <param name="source">The other sequences to concatenate.</param>
/// <returns></returns>
public static IEnumerable<TSource> ConcatMultiple<TSource>(this IEnumerable<TSource> first, params IEnumerable<TSource>[] source)
{
if (first == null)
throw new ArgumentNullException("first");
if (source.Any(x => (x == null)))
throw new ArgumentNullException("source");
return ConcatIterator<TSource>(source);
}
private static IEnumerable<TSource> ConcatIterator<TSource>(IEnumerable<TSource> first, params IEnumerable<TSource>[] source)
{
foreach (var iteratorVariable in first)
yield return iteratorVariable;
foreach (var enumerable in source)
{
foreach (var iteratorVariable in enumerable)
yield return iteratorVariable;
}
}
/// <summary>
/// Concatenates multiple sequences
/// </summary>
/// <typeparam name="TSource">The type of the elements of the input sequences.</typeparam>
/// <param name="source">The sequences to concatenate.</param>
/// <returns></returns>
public static IEnumerable<TSource> ConcatMultiple<TSource>(params IEnumerable<TSource>[] source)
{
if (source.Any(x => (x == null)))
throw new ArgumentNullException("source");
return ConcatIterator<TSource>(source);
}
private static IEnumerable<TSource> ConcatIterator<TSource>(params IEnumerable<TSource>[] source)
{
foreach (var enumerable in source)
{
foreach (var iteratorVariable in enumerable)
yield return iteratorVariable;
}
}
Join方法类似于SQL的join,其中列表是基于条件进行交叉引用,它不是字符串连接或添加到列表。 Union方法确实可以实现您想要的效果,Concat方法也可以,但两者都是惰性评估,并且有参数非空的要求。它们返回一个ConcatIterator或UnionIterator,如果重复调用可能会导致问题。急切的评估会产生不同的行为,如果这是您想要的,那么可以使用下面的扩展方法。
public static IEnumerable<T> myEagerConcat<T>(this IEnumerable<T> first,
IEnumerable<T> second)
{
return (first ?? Enumerable.Empty<T>()).Concat(
(second ?? Enumerable.Empty<T>())).ToList();
}
IEnumerable<T>.Concat()
,但今天我需要确保第二次枚举不会在第一次枚举结束之前被枚举。(例如,我不想同时运行两个数据库查询)。因此,下面的函数可以延迟枚举。 IEnumerable<T> DelayedConcat<T>(params Func<IEnumerable<T>>[] enumerableList)
{
foreach(var enumerable in enumerableList)
{
foreach (var item in enumerable())
{
yield return item;
}
}
}
使用方法:
return DelayedConcat(
() => GetEnumerable1(),
() => GetEnumerable2(),
// and so on.. () => GetEnumerable3(),
);
Func<IEnumerable<T>>
并确保在第一个枚举被耗尽之前不会创建第二个枚举。 - Gerardo Grignoli