将列表复制到新列表的适当方法是什么? 将列表复制到新列表的最有效方法是什么?
通过高效,而不是代码效率,更多的是在幕后框架意义上。
List<String>List2 = List.ToList();
或
List<String>List2 = new List<String>();
foreach (string item in List)
{
List2.Add(item);
}
更新
更高效的IL代码怎么样?
答案 0 :(得分:13)
鉴于List<T>
有一个IEnumerable<T>
构造函数,我更喜欢这种形式:
List<string> newList = new List<string>(otherList);
修改强>
正如Ondrej在下面的反编译代码中指出的那样,List<T>
的构造函数预先分配了数组的大小并将内容复制过来。这比创建一个新列表要快得多,然后迭代在另一个列表中单独添加项目,特别是在第二个示例中,您没有指定要预分配的项目数。
答案 1 :(得分:7)
ToList做了什么(缩短):
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
return new List<TSource>(source);
}
ctor做什么(缩短):
public List(IEnumerable<T> collection)
{
ICollection<T> collection2 = collection as ICollection<T>;
int count = collection2.Count;
this._items = new T[count];
collection2.CopyTo(this._items, 0);
this._size = count;
}
因此ToList()效率更高 - 它首先分配空间,然后一步复制所有项目。
答案 2 :(得分:5)
您可以使用IEnumerable<T>
List<T>
constructor
List<string> list1 = new List<string>();
// fill list1
List<string> list2 = new List<string>(list1);
答案 3 :(得分:2)
在效率方面,第一个会更快。 List<T>
的底层实现是一个ArrayList,因此当你调用.Add
时,你可能需要调整底层数组的大小。
另一方面,.ToList
可以确定新List
的正确初始大小,并避免foreach
技术遭受的重新分配操作。
考虑到这一点,我建议.ToList
。更少的代码,它会更快。
这是一个简单的程序,您可以运行以验证ToList
确实更快:
void Main()
{
List<int> items = new List<int>();
items = Enumerable.Range(0, 1000000).ToList();
CopyWithToList(items);
CopyWithForeach(items);
}
public void CopyWithToList<T>(List<T> list)
{
var sw = Stopwatch.StartNew();
List<T> copy = list.ToList();
sw.Stop();
Console.WriteLine("CopyWithToList: {0}", sw.Elapsed);
}
public void CopyWithForeach<T>(List<T> list)
{
var sw = Stopwatch.StartNew();
List<T> copy = new List<T>();
foreach (T item in list) {
copy.Add(item);
}
sw.Stop();
Console.WriteLine("CopyWithForeach: {0}", sw.Elapsed);
}
答案 4 :(得分:1)
我相信这两个例子完全相同,。ToList()可能会实现后者。
最佳表现是这样的:
List<String> list2 = new List<String>(list.Count);
foreach(String item in list)
list2.Add(item);
重要的是创建具有足够容量来保存其内容的list2。
如果您之后不需要修改任何一个列表,那么您只需要一个参考副本:
List<String> list2 = list;
答案 5 :(得分:1)
测试显示,最佳性能采用.ToList()
方法(对于包含21474836元素的列表,它在笔记本电脑Core i5 CPU上运行大约48毫秒)。
每个其他方法都比较慢,并且使用.Add()
的方法最差,而谈论性能。
以下是一些测试代码:
class Program
{
static void Main()
{
var list = new List<int>();
for (int i = 0; i < int.MaxValue / 100; i++)
{
list.Add(i);
}
TimeItAccurate(ListCopy_1, list, 10);
TimeItAccurate(ListCopy_2, list, 10);
TimeItAccurate(ListCopy_3, list, 10);
TimeItAccurate(ListCopy_4, list, 10);
TimeItAccurate(ListCopy_5, list, 10);
}
private static List<int> ListCopy_1(List<int> list)
{
var newList = list.ToList();
return newList;
}
private static List<int> ListCopy_2(List<int> list)
{
var newList = new List<int>(list.Count);
foreach (var i in list)
{
newList.Add(i);
}
return newList;
}
private static List<int> ListCopy_3(List<int> list)
{
var newList = new List<int>(list.ToArray());
return newList;
}
private static List<int> ListCopy_4(List<int> list)
{
var newList = new List<int>(list.Count);
newList.AddRange(list);
return newList;
}
private static List<int> ListCopy_5(List<int> list)
{
var newList = new List<int>(list);
return newList;
}
public static void TimeItAccurate<TIn, TResult>(Func<TIn, TResult> func, TIn argument, int iterationsCount)
{
#region Pre-heat
for (int i = 0; i < 10; i++)
{
var t = func.Invoke(argument);
}
#endregion
var stopwatch = new Stopwatch();
var result = default(TResult);
stopwatch.Start();
for (int i = 0; i < iterationsCount; i++)
{
result = func.Invoke(argument);
}
stopwatch.Stop();
Console.WriteLine("Result:\n{4}(...) == {0}\n\n{1} iterations done in {2} ms.\nAverage time: {3:f5} ms.",
result,
iterationsCount,
stopwatch.ElapsedMilliseconds,
stopwatch.ElapsedMilliseconds / (double)iterationsCount,
func.Method.Name);
}
}
结果:
Result (.ToList()):
ListCopy_1(...) == System.Collections.Generic.List`1[System.Int32]
10 iterations done in 474 ms.
Average time: 47.40000 ms.
Result (for-cycle with .Add()):
ListCopy_2(...) == System.Collections.Generic.List`1[System.Int32]
10 iterations done in 1896 ms.
Average time: 189.60000 ms.
Result (ctor with .ToArray()):
ListCopy_3(...) == System.Collections.Generic.List`1[System.Int32]
10 iterations done in 981 ms.
Average time: 98.10000 ms.
Result (.AddRange()):
ListCopy_4(...) == System.Collections.Generic.List`1[System.Int32]
10 iterations done in 959 ms.
Average time: 95.90000 ms.
Result (new List<int>(list)):
ListCopy_5(...) == System.Collections.Generic.List`1[System.Int32]
10 iterations done in 480 ms.
Average time: 48.00000 ms.