【问题标题】:Appending/concatenating two IEnumerable sequences附加/连接两个 IEnumerable 序列
【发布时间】:2011-02-10 19:53:10
【问题描述】:

我有两组数据行。它们都是 IEnumerable。我想将这两个列表附加/连接到一个列表中。我确信这是可行的。我不想做一个 for 循环,并注意到两个 List 上有一个 Union 方法和一个 Join 方法。有什么想法吗?

【问题讨论】:

  • 数据行的集合是同一类型吗?不同的类型?
  • @Obed....它们属于同一类型

标签: c# ienumerable unions


【解决方案1】:

假设您的对象属于同一类型,您可以使用UnionConcat。请注意,与 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 的实例的操作。

【讨论】:

  • @Adam....我说得太早了。我已经完成了联盟我得到了重复的记录。是否需要初始化某种关键属性?
  • @MikeTWebb: Union 有一个允许你指定IEqualityComparer 的重载。
  • @MikeTWebb:如果这个答案解决了你的问题,请记得采纳!谢谢。
【解决方案2】:

我刚刚遇到了需要连接多个序列的类似情况。

在 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;
    }
}

【讨论】:

    【解决方案3】:

    Join 方法类似于 SQL 连接,其中列表基于条件交叉引用,它不是字符串连接或添加到列表。 Union 方法确实可以满足您的需求,Concat 方法也是如此,但两者都是 LAZY 评估,并且要求参数不为空。它们返回 ConcatIterator 或 UnionIterator 和 if called repeatedly this could cause problems。急切的评估会导致不同的行为,如果这是您想要的,那么可以使用如下扩展方法。

    public static IEnumerable<T> myEagerConcat<T>(this IEnumerable<T> first,
                                                       IEnumerable<T> second)
    {
        return (first ?? Enumerable.Empty<T>()).Concat(
               (second ?? Enumerable.Empty<T>())).ToList();
    }
    

    【讨论】:

      【解决方案4】:

      第二个和后续枚举的延迟调用

      我通常使用 Linq IEnumerable&lt;T&gt;.Concat() 但今天我需要 100% 确定直到第一个枚举被处理到最后才枚举第二个枚举。 (例如,我不想同时运行的两个数据库查询)。所以下面的函数可以延迟枚举。

          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(),
                      );
      

      在本例中,GetEnumerable2 函数调用将被延迟,直到 GetEnumerable1 被枚举完毕。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-19
      • 2015-01-19
      • 1970-01-01
      • 2022-11-09
      • 2022-01-11
      • 2020-01-18
      • 1970-01-01
      相关资源
      最近更新 更多