.NET List<T> Concat与AddRange的区别

120

AddRangeConcat函数在泛型列表中有何区别?是否建议使用其中之一?

3个回答

146

它们具有完全不同的语义。

AddRange通过将其他项添加到列表中来修改列表。

Concat返回一个包含列表和其他项的新序列,而不会修改列表。

选择具有所需语义的任何一个。


2
在一个紧密的循环中,最好使用add range,以免由于所有内部的newing和GC操作而损失性能。 - johnc
54
实际上,由于延迟执行的原因,使用Concat可能更快,因为它避免了对象分配 - Concat不会复制任何东西,它只是在列表之间创建链接,所以当枚举并到达一个列表的末尾时,它会自动地将您带到下一个列表的开头! - Greg Beech
@GregBeech 我知道这是一个很旧的评论,但你是错的。首先,延迟执行与性能无关。其次,你混淆了两者(尽管在实际回复中说得正确)。Concat会在内存中创建一个新对象,而不会修改其他两个序列,这就是为什么它比AddRange慢的原因。当处理小序列时,差异并不明显,但当处理大型集合时,必须使用AddRange,因为它明显更快(除非由于某种原因需要保持两个序列不被修改)。 - Emre Bener
@GregBeech 我知道这是一个很旧的评论,但你是错的。首先,延迟执行与性能无关。其次,你混淆了这两个概念(尽管你在实际回复中说得正确)。Concat会在内存中创建一个新的对象,而不会修改其他两个序列,这就是为什么它比AddRange慢的原因。当处理小序列时,差异不明显,但当处理大型集合时,必须使用AddRange,因为它明显更快(除非你有某种原因需要保持这两个序列不被修改)。 - undefined
@johnc 你说得对,AddRange更快,因为它不会创建一个全新的对象,然而,当处理小序列时,速度差异可以忽略不计。 - Emre Bener
@johnc 你说得对,AddRange更快,因为它不会创建一个全新的对象,不过,当处理小序列时,速度差异微乎其微。 - undefined

46

AddRange 会直接对调用它的列表进行改变,而 Concat 则创建一个新的列表。因此,它们具有不同的用途。

Concat 是一个扩展方法,适用于任何 IEnumerable<T>,返回一个 IEnumerable<T>,需要使用 .ToList() 将其转换为新的列表。

如果您想扩展现有列表的内容,请使用 AddRange

如果您要从两个 IEnumerable<T> 源创建一个新列表,则使用带有 .ToListConcat。这样可以避免改变任意一个源。

如果您只需要枚举两个列表(或任何其他 IEnumerable)的内容,则每次都简单地使用 Concat,这样可以不必分配新的内存来保存合并后的列表。


3
确实,如果你忘记使用 'tolist',concat函数会默默无声地什么都不做。+1 - smirkingman

11

我发现了一篇有趣的文章,讨论了这两种结构之间的差别并比较它们的性能...

主要思想是当涉及到大型集合时,AddRange的速度要快得多。

在这里链接

希望对你有所帮助,


5
我进行了一项测试,对比了使用一个包含1000个元素的List<KeyValuePair<string, string>>对象进行100次连接/添加操作时的ConcatAddRange方法。测试结果表明,AddRange速度更快。具体数据如下:使用AddRange仅需13毫秒,而使用Concat().ToList()则需要花费16000毫秒,当仅在最后执行ToList操作时,使用IEnumerableConcat方法仅需要2700毫秒。 - Andrew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接