【问题标题】:Is there an easy way to append one IList<MyType> to another?有没有一种简单的方法可以将一个 IList<MyType> 附加到另一个?
【发布时间】:2012-03-01 16:42:23
【问题描述】:

这里是一些示例代码:

IList<MyType> myList1=new List<MyType>();
IList<MyType> myList2=new List<MyType>();

// Populate myList1
...
// Add contents of myList1 to myList2
myList2.Add(myList1); // Does not compile

如何将一个列表的内容添加到另一个列表 - 有什么方法吗?

【问题讨论】:

  • targetList.AddRange(sourceList);
  • @vulkanino AddRangeList&lt;&gt; 的方法,而不是IList&lt;&gt;
  • 是的,对不起,我的意思是我没有指定的演员表。
  • @vulkanino a cast 仅在对象的运行时类型实际上是 List&lt;MyType&gt; 或派生类型时才有效。 IList&lt;MyType&gt; 可以引用类型为MyType[] 的对象;这会引发异常。
  • 为什么这么多回答的人反对使用简单的 for 循环,而是宁愿重新创建一个或多个完整列表,这样他们就可以说他们使用了 LINQ 并少写了一行代码。 for 循环什么时候变得邪恶了?

标签: c# .net c#-4.0 .net-4.0


【解决方案1】:

没有很好的内置方法可以做到这一点。你真正想要的是一个AddRange 方法,但它在IList&lt;T&gt; (或它的层次结构)上不存在。不过,为此定义一个新的扩展方法是直截了当的

public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> enumerable) {
  foreach (var cur in enumerable) {
    collection.Add(cur);
  }
}

myList2.AddRange(myList1);

【讨论】:

  • 我是赞成票,而不是反对票,但这可能是因为“为这样一个简单的任务声明一个方法太过分了”。我的回答也受到了类似的批评;该方法可能是 5 或 6 行代码,在调用站点仅节省了几行代码。但是调用站点被更改为单个表达式,而不是 2 或 3 个语句,当然,如果该方法被多次使用,代码行数就会净减少。
  • @phoog 是的,如果我只使用一次,我会内联foreach。这是标准扩展方法之一(如ForEach),我只是在我编写的每个项目中定义它。它们非常有用。
  • 即使添加更多代码行,我也会挖掘这个解决方案,因为代码在调用点会更干净。在通话时,我完全是为了清楚起见。而且您必须知道,一旦编写完成,您会发现自己再次使用它,因为它出现在 IntelliSense 中。
  • @Tim:那是在 IEnumerable 上,而不是 @IList
  • @RhinoDevX64 JaredPar 的扩展方法可以应用于任何ICollection&lt;T&gt;,例如包括HashSet&lt;T&gt;
【解决方案2】:

如果您将两种列表类型都声明为具体的List 而不是IList,则可以使用AddRange 方法:

List<MyType> myList1=new List<MyType>();
List<MyType> myList2=new List<MyType>();

myList2.AddRange(myList1);

否则您可以使用 LINQ 将两者结合起来:

using System.Linq;

IList<MyType> myList1=new List<MyType>();
IList<MyType> myList2=new List<MyType>();

var newList = myList1.Concat(myList2);

【讨论】:

  • 虽然 LINQ 解决方案在调用时看起来不错,但它在使用组合项目创建新列表时效率低下。
  • 迈克尔,任何方式都有优缺点(:
【解决方案3】:

使用 Enumerablr 扩展,

myList2=new List<MyType>(myList2.Concat(myList1))

顺便说一句,如果你不填充 myList2,你可以根据 myLis1 创建它。

编辑

我尝试研究几个案例的性能

1) 通过添加添加范围

List2.AddRange(List1);

public static class AddRangeUtils
{
    public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> enumerable)
    {
        foreach (var cur in enumerable)
        {
            collection.Add(cur);
        }
    }
}

2) 连接

List2 = new List<TestClass>(List2.Concat(List1))

3) 预定义收集计数 1

var thirdList = new List<TestClass>(List2.Count + List1.Count);
foreach (var testClass in List1)
{
   thirdList.Add(testClass);
}
foreach (var testClass in List2)
{
   thirdList.Add(testClass);
}
List2 = thirdList;

4) 预定义收集计数 2

var thirdList = new List<TestClass>(List2.Count + List1.Count);
thirdList.AddRange(List1);
thirdList.AddRange(List2);
List2 = thirdList;

Collection's Count 是每个列表 List1 和 List2 的元素计数: 并得出这样的结果(不同集合的长度)

【讨论】:

  • 这不会将值添加到myList2。相反,它会创建一个新的 List&lt;T&gt; 值。这与 OP 的要求不同。
  • 当然,您需要将其分配给 myList。好的,我已经修改了
  • 如果附加多个列表,这将具有可怕的时间复杂度。
  • 这将花费很多时间,即使是从两个数组复制到第三个数组,或者从一个列表中迭代每个项目并通过 Add 方法添加。
【解决方案4】:

如果第二个列表的运行时类型是List&lt;T&gt;,您可以强制转换为该类型并使用AddRange() 方法。

否则,您必须自己使用循环来完成。或者,您可以使用 linq 创建一个包含两个源列表内容的新列表。

【讨论】:

    【解决方案5】:

    我使用了这一行方法:

    Array.ForEach(ilist1.ToArray(), x =&gt; ilist2.Add(x));

    【讨论】:

      猜你喜欢
      • 2012-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-04
      • 1970-01-01
      • 1970-01-01
      • 2012-01-21
      • 2012-02-25
      相关资源
      最近更新 更多