首页 文章

在LINQ查询中调用ToList()或ToArray()会更好吗?

提问于
浏览
439

我经常遇到我想在我声明它的地方评估查询的情况 . 这通常是因为我需要多次迭代它并且计算起来很昂贵 . 例如:

string raw = "...";
var lines = (from l in raw.Split('\n')
             let ll = l.Trim()
             where !string.IsNullOrEmpty(ll)
             select ll).ToList();

这很好用 . But 如果我不打算修改结果,那么我不妨调用 ToArray() 而不是 ToList() .

我想知道 ToArray() 是否通过首先调用 ToList() 来实现,因此比调用 ToList() 更节省内存 .

我疯了吗?我应该只是打电话给 ToArray() - 知道内存不会被分配两次是安全的吗?

15 回答

  • 12

    除非您只需要一个数组来满足其他约束,否则您应该使用 ToList . 在大多数情况下, ToArray 将分配比 ToList 更多的内存 .

    两者都使用数组进行存储,但 ToList 具有更灵活的约束 . 它需要数组至少与集合中元素的数量一样大 . 如果数组较大,那不是问题 . 但是 ToArray 需要将数组的大小精确地调整为元素的数量 .

    为了满足这个约束, ToArray 经常比 ToList 多做一次分配 . 一旦它有一个足够大的数组,它就会分配一个完全正确大小的数组,并将元素复制回该数组 . 唯一能避免这种情况的是当数组的增长算法恰好与需要存储的元素数量一致时(绝对是少数) .

    EDIT

    有几个人问我在 List<T> 值中有多余的未使用内存的后果 .

    这是一个有效的问题 . 如果创建的集合是长期存在的,在创建之后永远不会被修改并且很有可能在Gen2堆中登陆,那么你可能最好在前面额外分配 ToArray .

    总的来说,虽然我发现这是罕见的情况 . 更常见的是看到很多 ToArray 调用会立即传递给内存的其他短暂使用,在这种情况下 ToList 明显更好 .

    这里的关键是剖析,剖析,然后再详细介绍一些 .

  • 12

    性能差异无关紧要,因为 List<T> 实现为动态大小的数组 . 调用 ToArray() (使用内部 Buffer<T> 类来增长数组)或 ToList() (调用 List<T>(IEnumerable<T>) 构造函数)将最终成为将它们放入数组并增长数组直到它适合所有数组的问题 .

    如果您希望具体确认这一事实,请查看Reflector中相关方法的实现 - 您将看到它们归结为几乎完全相同的代码 .

  • 9

    (七年后......)

    其他(好)答案集中在将发生的微观性能差异上 .

    这篇文章只是一个补充,提到 semantic difference 存在于数组( T[] )产生的 IEnumerator<T>List<T> 返回的数据之间 .

    通过示例最佳说明:

    IList<int> source = Enumerable.Range(1, 10).ToArray();  // try changing to .ToList()
    
    foreach (var x in source)
    {
      if (x == 5)
        source[8] *= 100;
      Console.WriteLine(x);
    }
    

    上面的代码将运行,没有异常并产生输出:

    1
    2
    3
    4
    5
    6
    7
    8
    900
    10
    

    这表明 int[] 返回的 IEnumarator<int> 无法跟踪自创建枚举器以来阵列是否已被修改 .

    请注意,我将局部变量 source 声明为 IList<int> . 通过这种方式,我确保C#编译器不会将 foreach 语句优化为等同于 for (var idx = 0; idx < source.Length; idx++) { /* ... */ } 循环的内容 . 如果我使用 var source = ...; ,这就是C#编译器可能会做的事情 . 在我当前版本的.NET框架中,这里使用的实际枚举器是非公共引用类型 System.SZArrayHelper+SZGenericArrayEnumerator1[System.Int32]` ,但当然这是一个实现细节 .

    现在,如果我将 .ToArray() 更改为 .ToList() ,我只会:

    1
    2
    3
    4
    5
    

    随后是 System.InvalidOperationException 爆炸说:

    收藏被修改;枚举操作可能无法执行 .

    在这种情况下,底层枚举器是public mutable value-type [System.Collections.Generic.List1+Enumerator[System.Int32]](https://msdn.microsoft.com/en-us/library/x854yt9s.aspx)(在这种情况下,在IEnumerator<int>框内装箱,因为我使用IList<int>` ) .

    In conclusion,List<T> 生成的枚举器会跟踪列表在枚举期间是否更改,而 T[] 生成的枚举器则不会 . 因此,在 .ToList().ToArray() 之间进行选择时,请考虑这种差异 .

    人们经常添加一个额外的 .ToArray().ToList() 来绕过一个集合跟踪调查员在整个生命周期内是否被修改过 .

    (如果有人想知道 List<> 如何跟踪集合是否被修改,则此类中有一个私有字段 _version ,每次更新 List<> 时都会更改 . )

  • 30

    我同意@mquander的观点,即性能差异应该是微不足道的 . 但是,我想确定它的基准,所以我做了 - 而且它是微不足道的 .

    Testing with List<T> source:
    ToArray time: 1934 ms (0.01934 ms/call), memory used: 4021 bytes/array
    ToList  time: 1902 ms (0.01902 ms/call), memory used: 4045 bytes/List
    
    Testing with array source:
    ToArray time: 1957 ms (0.01957 ms/call), memory used: 4021 bytes/array
    ToList  time: 2022 ms (0.02022 ms/call), memory used: 4045 bytes/List
    

    每个源数组/ List都有1000个元素 . 所以你可以看到时间和内存的差异可以忽略不计 .

    我的结论是:你不妨使用 ToList() ,因为 List<T> 提供的功能比数组更多,除非几个字节的内存对你很重要 .

  • 24

    内存将始终分配两次 - 或接近该内存 . 由于无法调整数组大小,因此两种方法都将使用某种机制来收集不断增长的集合中的数据 . (好吧,List是一个不断增长的集合 . )

    List使用数组作为内部存储,并在需要时将容量加倍 . 这意味着平均2/3的项目至少重新分配一次,其中一半重新分配至少两次,其中一半重新分配至少三次,依此类推 . 这意味着每个项目平均重新分配1.3次,这不是很大的开销 .

    还要记住,如果要收集字符串,集合本身只包含对字符串的引用,字符串本身不会重新分配 .

  • 15

    如果您在 IEnumerable<T> (例如来自ORM)上使用它,通常首选 ToList() . 如果开头不知道序列的长度, ToArray() 会创建像List这样的动态长度集合,然后将其转换为数组,这需要额外的时间 .

  • 277

    Edit :此答案的最后部分无效 . 但是,其余的仍然是有用的信息,所以我会留下它 .

    我知道这是一个老帖子,但在有了同样的问题并做了一些研究后,我发现了一些可能值得分享的有趣内容 .

    首先,我同意@mquander和他的回答 . 他说性能方面是正确的,两者是相同的 .

    但是,我一直在使用Reflector来查看 System.Linq.Enumerable 扩展名称空间中的方法,我注意到了一个非常常见的优化 .
    只要有可能, IEnumerable<T> 源将转换为 IList<T>ICollection<T> 以优化方法 . 例如,请查看 ElementAt(int) .

    有趣的是,微软选择仅针对 IList<T> 进行优化,而不是 IList . 看起来微软更喜欢使用 IList<T> 界面 .

    System.Array仅实现IList,因此它不会受益于任何这些扩展优化 . 因此,我认为最佳做法是使用.ToList()方法 . 如果您使用任何扩展方法,或将列表传递给另一个方法,则可能会针对IList <T>进行优化 .

  • 7

    根据理想的设计选择,您应该根据 ToListToArray 做出决定 . 如果您想要一个只能通过索引进行迭代和访问的集合,请选择 ToArray . 如果你想在以后添加和删除集合的其他功能没有太多麻烦,那么做一个 ToList (不是真的你不能添加到一个数组,但这通常不适合它) .

    如果性能很重要,您还应该考虑哪些操作更快 . 实际上,你不会拨打 ToListToArray 一百万次,但可能会对获得的收藏品进行一百万次的处理 . 在这方面 [] 更好,因为 List<>[] 并且有一些开销 . 请参阅此主题以进行效率比较:Which one is more efficient : List<int> or int[]

    在我不久前的测试中,我发现 ToArray 更快 . 而且我不确定测试有多么偏差 . 但性能差异是如此微不足道,只有当您在循环中运行这些查询数百万次时才能注意到这一点 .

  • 4

    一个非常晚的答案,但我认为这将有助于谷歌 .

    他们在使用linq创建时都很糟糕 . 它们都实现了相同的代码 resize buffer if necessary . ToArray 内部使用一个类将 IEnumerable<> 转换为数组,方法是分配一个包含4个元素的数组 . 如果这还不够,可以通过创建一个新的数组,将当前大小加倍,并将当前数组复制到该数组,从而使其大小增加一倍 . 最后,它会分配一个新的项目数量 . 如果您的查询返回129元素然后ToArray将进行6次分配和内存复制操作以创建256个元素数组,而不是另一个129要返回的数组 . 对于记忆效率这么多 .

    ToList执行相同的操作,但它会跳过最后一次分配,因为您可以在将来添加项目 . 列表不关心它是从linq查询创建还是手动创建 .

    创建列表更好的内存,但更糟糕的是cpu,因为列表是一个通用的解决方案,每个操作都需要范围检查,除了.net的内部范围检查数组 .

    因此,如果您将遍历结果集太多次,那么数组是好的,因为它意味着比列表更少的范围检查,并且编译器通常优化数组以进行顺序访问 .

    如果在创建容量参数时指定容量参数,则列表的初始化分配会更好 . 在这种情况下,假设您知道结果大小,它将仅分配一次数组 . linq的 ToList 没有指定提供它的重载,因此我们必须创建扩展方法,创建具有给定容量的列表,然后使用 List<>.AddRange .

    要完成这个答案,我必须写下面的句子

    • 最后,您可以使用ToArray或ToList,性能不会如此不同(请参阅@EMP的答案) .

    • 您正在使用C# . 如果您需要性能,那么不要担心编写高性能代码,但担心不编写糟糕的性能代码 .

    • 始终以x64为目标,以获得高性能代码 . AFAIK,x64 JIT基于C编译器,并做了一些有趣的事情,如尾递归优化 .

    • 使用4.5,您还可以享受配置文件引导优化和多核JIT .

    • 最后,您可以使用async / await模式更快地处理它 .

  • 1

    我发现人们在这里做的其他基准测试缺乏,所以这里是我的解决方案 . 如果您发现我的方法有问题,请告诉我 .

    /* This is a benchmarking template I use in LINQPad when I want to do a
     * quick performance test. Just give it a couple of actions to test and
     * it will give you a pretty good idea of how long they take compared
     * to one another. It's not perfect: You can expect a 3% error margin
     * under ideal circumstances. But if you're not going to improve
     * performance by more than 3%, you probably don't care anyway.*/
    void Main()
    {
        // Enter setup code here
        var values = Enumerable.Range(1, 100000)
            .Select(i => i.ToString())
            .ToArray()
            .Select(i => i);
        values.GetType().Dump();
        var actions = new[]
        {
            new TimedAction("ToList", () =>
            {
                values.ToList();
            }),
            new TimedAction("ToArray", () =>
            {
                values.ToArray();
            }),
            new TimedAction("Control", () =>
            {
                foreach (var element in values)
                {
                    // do nothing
                }
            }),
            // Add tests as desired
        };
        const int TimesToRun = 1000; // Tweak this as necessary
        TimeActions(TimesToRun, actions);
    }
    
    
    #region timer helper methods
    // Define other methods and classes here
    public void TimeActions(int iterations, params TimedAction[] actions)
    {
        Stopwatch s = new Stopwatch();
        int length = actions.Length;
        var results = new ActionResult[actions.Length];
        // Perform the actions in their initial order.
        for (int i = 0; i < length; i++)
        {
            var action = actions[i];
            var result = results[i] = new ActionResult { Message = action.Message };
            // Do a dry run to get things ramped up/cached
            result.DryRun1 = s.Time(action.Action, 10);
            result.FullRun1 = s.Time(action.Action, iterations);
        }
        // Perform the actions in reverse order.
        for (int i = length - 1; i >= 0; i--)
        {
            var action = actions[i];
            var result = results[i];
            // Do a dry run to get things ramped up/cached
            result.DryRun2 = s.Time(action.Action, 10);
            result.FullRun2 = s.Time(action.Action, iterations);
        }
        results.Dump();
    }
    
    public class ActionResult
    {
        public string Message { get; set; }
        public double DryRun1 { get; set; }
        public double DryRun2 { get; set; }
        public double FullRun1 { get; set; }
        public double FullRun2 { get; set; }
    }
    
    public class TimedAction
    {
        public TimedAction(string message, Action action)
        {
            Message = message;
            Action = action;
        }
        public string Message { get; private set; }
        public Action Action { get; private set; }
    }
    
    public static class StopwatchExtensions
    {
        public static double Time(this Stopwatch sw, Action action, int iterations)
        {
            sw.Restart();
            for (int i = 0; i < iterations; i++)
            {
                action();
            }
            sw.Stop();
    
            return sw.Elapsed.TotalMilliseconds;
        }
    }
    #endregion
    

    你可以download the LINQPad Script here .

    结果:
    ToArray vs ToList performance

    调整上面的代码,你会发现:

    • dealing with smaller arrays时,差异不太明显 .
      More iterations, but smaller arrays

    • 处理 int 而不是 string 时,差异不太明显 .

    • 使用大 struct 而不是 string 一般需要花费更多时间,但并没有真正改变比率 .

    这与最高投票答案的结论一致:

    • 除非您的代码经常产生许多大型数据列表,否则您不太可能注意到性能差异 . (每个创建1000个100K字符串列表时只有200ms的差异 . )

    • ToList() 始终如一地运行得更快,如果您不打算长时间坚持使用结果,那将是更好的选择 .

    更新

    @JonHanna指出,根据 Select 的实现, ToList()ToArray() 实现可以提前预测产生的集合大小 . 目前用 Where(i => true) yields very similar results替换上面代码中的 .Select(i => i) ,无论.NET实现如何,更有可能这样做 .

    Benchmark using Where instead of Select

  • 19

    这是一个古老的问题 - 但是为了绊倒它的用户的利益,还有“Memoizing”Enumerable的替代方案 - 它具有缓存和停止Linq语句的多个枚举的效果,这就是ToArray()即使从不使用列表或数组的集合属性,也会使用ToList() .

    Memoize在RX / System.Interactive lib中可用,并在此解释:More LINQ with System.Interactive

    (来自Bart De'Smet's blog,如果您正在使用Linq对象很多,这是 highly 建议阅读)

  • 155

    一种选择是添加自己的扩展方法,返回 readonly ICollection<T> . 当您不想使用数组/列表的索引属性或从列表中添加/删除时,这可能比使用 ToListToArray 更好 .

    public static class EnumerableExtension
    {
        /// <summary>
        /// Causes immediate evaluation of the linq but only if required.
        /// As it returns a readonly ICollection, is better than using ToList or ToArray
        /// when you do not want to use the indexing properties of an IList, or add to the collection.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="enumerable"></param>
        /// <returns>Readonly collection</returns>
        public static ICollection<T> Evaluate<T>(this IEnumerable<T> enumerable)
        {
            //if it's already a readonly collection, use it
            var collection = enumerable as ICollection<T>;
            if ((collection != null) && collection.IsReadOnly)
            {
                return collection;
            }
            //or make a new collection
            return enumerable.ToList().AsReadOnly();
        }
    }
    

    单元测试:

    [TestClass]
    public sealed class EvaluateLinqTests
    {
        [TestMethod]
        public void EvalTest()
        {
            var list = new List<int> {1, 2, 3};
            var linqResult = list.Select(i => i);
            var linqResultEvaluated = list.Select(i => i).Evaluate();
            list.Clear();
            Assert.AreEqual(0, linqResult.Count());
            //even though we have cleared the underlying list, the evaluated list does not change
            Assert.AreEqual(3, linqResultEvaluated.Count());
        }
    
        [TestMethod]
        public void DoesNotSaveCreatingListWhenHasListTest()
        {
            var list = new List<int> {1, 2, 3};
            var linqResultEvaluated = list.Evaluate();
            //list is not readonly, so we expect a new list
            Assert.AreNotSame(list, linqResultEvaluated);
        }
    
        [TestMethod]
        public void SavesCreatingListWhenHasReadonlyListTest()
        {
            var list = new List<int> {1, 2, 3}.AsReadOnly();
            var linqResultEvaluated = list.Evaluate();
            //list is readonly, so we don't expect a new list
            Assert.AreSame(list, linqResultEvaluated);
        }
    
        [TestMethod]
        public void SavesCreatingListWhenHasArrayTest()
        {
            var list = new[] {1, 2, 3};
            var linqResultEvaluated = list.Evaluate();
            //arrays are readonly (wrt ICollection<T> interface), so we don't expect a new object
            Assert.AreSame(list, linqResultEvaluated);
        }
    
        [TestMethod]
        [ExpectedException(typeof (NotSupportedException))]
        public void CantAddToResultTest()
        {
            var list = new List<int> {1, 2, 3};
            var linqResultEvaluated = list.Evaluate();
            Assert.AreNotSame(list, linqResultEvaluated);
            linqResultEvaluated.Add(4);
        }
    
        [TestMethod]
        [ExpectedException(typeof (NotSupportedException))]
        public void CantRemoveFromResultTest()
        {
            var list = new List<int> {1, 2, 3};
            var linqResultEvaluated = list.Evaluate();
            Assert.AreNotSame(list, linqResultEvaluated);
            linqResultEvaluated.Remove(1);
        }
    }
    
  • 3

    老问题,但新的提问者在任何时候 .

    根据System.Linq.Enumerable的来源, ToList 只返回new List(source),而 ToArray 使用new Buffer<T>(source).ToArray()返回 T[] .

    关于内存分配:

    IEnumerable<T> only 对象上运行时, ToArray 会比 ToList 再分配一次内存 . 但是在大多数情况下你不必关心它,因为GC会在需要时进行垃圾收集 .

    关于运行时效率:

    那些质疑这个问题的人可以运行以下代码你自己的机器,你会得到你的答案 .

    class PersonC
    {
        public Guid uuid;
        public string name;
        public int age;
        public bool sex;
        public DateTime BirthDay;
        public double weight;
    }
    
    struct PersonS
    {
        public Guid uuid;
        public string name;
        public int age;
        public bool sex;
        public DateTime BirthDay;
        public double weight;
    }
    
    class PersonT<T> : IEnumerable<T>
    {
        private List<T> items;
        public PersonT(IEnumerable<T> init)
        {
            items = new List<T>(init);
        }
    
        public IEnumerator<T> GetEnumerator() => items.GetEnumerator();
        IEnumerator IEnumerable.GetEnumerator() => items.GetEnumerator();
    }
    
    private IEnumerable<PersonC> C(int count)
    {
        for (var i = 0; i < count; ++i)
        {
            var guid = Guid.NewGuid();
            var guidBytes = guid.ToByteArray(); //16 bytes
            yield return new PersonC
            {
                uuid = guid,
                name = guid.ToString(),
                age = guidBytes[0] ^ guidBytes[7],
                sex = guidBytes[14] % 2 == 0,
                BirthDay = DateTime.Now.AddDays(-guidBytes[11] * 18),
                weight = guidBytes[12] * 100
            };
        }
    }
    
    private IEnumerable<PersonS> S(int count)
    {
        for (var i = 0; i < count; ++i)
        {
            var guid = Guid.NewGuid();
            var guidBytes = guid.ToByteArray(); //16 bytes
            yield return new PersonS
            {
                uuid = guid,
                name = guid.ToString(),
                age = guidBytes[0] ^ guidBytes[7],
                sex = guidBytes[14] % 2 == 0,
                BirthDay = DateTime.Now.AddDays(-guidBytes[11] * 18),
                weight = guidBytes[12] * 100
            };
        }
    }
    
    private void MakeLog(string test, List<long> log) =>
        Console.WriteLine("{0} {1} ms -> [{2}]",
            test,
            log.Average(),
            string.Join(", ", log)
        );
    
    private void Test1(int times, int count)
    {
        var test = Enumerable.Range(1, times).ToArray();
    
        MakeLog("C.ToList", test.Select(o =>
        {
            var sw = new Stopwatch();
            GC.Collect();
            sw.Start();
            var ret = C(count).ToList();
            sw.Stop();
            return sw.ElapsedMilliseconds;
        }).ToList());
    
        MakeLog("C.ToArray", test.Select(o =>
        {
            var sw = new Stopwatch();
            GC.Collect();
            sw.Start();
            var ret = C(count).ToArray();
            sw.Stop();
            return sw.ElapsedMilliseconds;
        }).ToList());
    
        MakeLog("S.ToList", test.Select(o =>
        {
            var sw = new Stopwatch();
            GC.Collect();
            sw.Start();
            var ret = S(count).ToList();
            sw.Stop();
            return sw.ElapsedMilliseconds;
        }).ToList());
    
        MakeLog("S.ToArray", test.Select(o =>
        {
            var sw = new Stopwatch();
            GC.Collect();
            sw.Start();
            var ret = S(count).ToArray();
            sw.Stop();
            return sw.ElapsedMilliseconds;
        }).ToList());
    }
    
    private void Test2(int times, int count)
    {
        var test = Enumerable.Range(1, times).ToArray();
    
        var dataC1 = new PersonT<PersonC>(C(count));
        var dataS1 = new PersonT<PersonS>(S(count));
    
        MakeLog("C1.ToList", test.Select(o =>
        {
            var sw = new Stopwatch();
            GC.Collect();
            sw.Start();
            var ret = dataC1.ToList();
            sw.Stop();
            return sw.ElapsedMilliseconds;
        }).ToList());
    
        MakeLog("C1.ToArray", test.Select(o =>
        {
            var sw = new Stopwatch();
            GC.Collect();
            sw.Start();
            var ret = dataC1.ToArray();
            sw.Stop();
            return sw.ElapsedMilliseconds;
        }).ToList());
    
        MakeLog("S1.ToList", test.Select(o =>
        {
            var sw = new Stopwatch();
            GC.Collect();
            sw.Start();
            var ret = dataS1.ToList();
            sw.Stop();
            return sw.ElapsedMilliseconds;
        }).ToList());
    
        MakeLog("S1.ToArray", test.Select(o =>
        {
            var sw = new Stopwatch();
            GC.Collect();
            sw.Start();
            var ret = dataS1.ToArray();
            sw.Stop();
            return sw.ElapsedMilliseconds;
        }).ToList());
    }
    
    private void Test3(int times, int count)
    {
        var test = Enumerable.Range(1, times).ToArray();
    
        var dataC2 = (ICollection<PersonC>) new List<PersonC>(C(count));
        var dataS2 = (ICollection<PersonS>) new List<PersonS>(S(count));
    
        MakeLog("C2.ToList", test.Select(o =>
        {
            var sw = new Stopwatch();
            GC.Collect();
            sw.Start();
            var ret = dataC2.ToList();
            sw.Stop();
            return sw.ElapsedMilliseconds;
        }).ToList());
    
        MakeLog("C2.ToArray", test.Select(o =>
        {
            var sw = new Stopwatch();
            GC.Collect();
            sw.Start();
            var ret = dataC2.ToArray();
            sw.Stop();
            return sw.ElapsedMilliseconds;
        }).ToList());
    
        MakeLog("S2.ToList", test.Select(o =>
        {
            var sw = new Stopwatch();
            GC.Collect();
            sw.Start();
            var ret = dataS2.ToList();
            sw.Stop();
            return sw.ElapsedMilliseconds;
        }).ToList());
    
        MakeLog("S2.ToArray", test.Select(o =>
        {
            var sw = new Stopwatch();
            GC.Collect();
            sw.Start();
            var ret = dataS2.ToArray();
            sw.Stop();
            return sw.ElapsedMilliseconds;
        }).ToList());
    }
    
    private void TestMain()
    {
        const int times = 100;
        const int count = 1_000_000 + 1;
        Test1(times, count);
        Test2(times, count);
        Test3(times, count);
    }
    

    我在我的机器上得到了这些结果:

    第1组:

    C.ToList 761.79 ms -> [775, 755, 759, 759, 756, 759, 765, 750, 757, 762, 759, 754, 757, 753, 763, 753, 759, 756, 768, 754, 763, 757, 757, 777, 780, 758, 754, 758, 762, 754, 758, 757, 763, 758, 760, 754, 761, 755, 764, 847, 952, 755, 747, 763, 760, 758, 754, 763, 761, 758, 750, 764, 757, 763, 762, 756, 753, 759, 759, 757, 758, 779, 765, 760, 760, 756, 760, 756, 755, 764, 759, 753, 757, 760, 752, 764, 758, 760, 758, 760, 755, 761, 751, 753, 761, 762, 761, 758, 759, 752, 765, 756, 760, 755, 757, 753, 760, 751, 755, 779]
    C.ToArray 782.56 ms -> [783, 774, 771, 771, 773, 774, 775, 775, 772, 770, 771, 774, 771, 1023, 975, 772, 767, 776, 771, 779, 772, 779, 775, 771, 775, 773, 775, 771, 765, 774, 770, 781, 772, 771, 781, 762, 817, 770, 775, 779, 769, 774, 763, 775, 777, 769, 777, 772, 775, 778, 775, 771, 770, 774, 772, 769, 772, 769, 774, 775, 768, 775, 769, 774, 771, 776, 774, 773, 778, 769, 778, 767, 770, 787, 783, 779, 771, 768, 805, 780, 779, 767, 773, 771, 773, 785, 1044, 853, 775, 774, 775, 771, 770, 769, 770, 776, 770, 780, 821, 770]
    S.ToList 704.2 ms -> [687, 702, 709, 691, 694, 710, 696, 698, 700, 694, 701, 719, 706, 694, 702, 699, 699, 703, 704, 701, 703, 705, 697, 707, 691, 697, 707, 692, 721, 698, 695, 700, 704, 700, 701, 710, 700, 705, 697, 711, 694, 700, 695, 698, 701, 692, 696, 702, 690, 699, 708, 700, 703, 714, 701, 697, 700, 699, 694, 701, 697, 696, 699, 694, 709, 1068, 690, 706, 699, 699, 695, 708, 695, 704, 704, 700, 695, 704, 695, 696, 702, 700, 710, 708, 693, 697, 702, 694, 700, 706, 699, 695, 706, 714, 704, 700, 695, 697, 707, 704]
    S.ToArray 742.5 ms -> [742, 743, 733, 745, 741, 724, 738, 745, 728, 732, 740, 727, 739, 740, 726, 744, 758, 732, 744, 745, 730, 739, 738, 723, 745, 757, 729, 741, 736, 724, 744, 756, 739, 766, 737, 725, 741, 742, 736, 748, 742, 721, 746, 1043, 806, 747, 731, 727, 742, 742, 726, 738, 746, 727, 739, 743, 730, 744, 753, 741, 739, 746, 728, 740, 744, 734, 734, 738, 731, 747, 736, 731, 765, 735, 726, 740, 743, 730, 746, 742, 725, 731, 757, 734, 738, 741, 732, 747, 744, 721, 742, 741, 727, 745, 740, 730, 747, 760, 737, 740]
    
    C1.ToList 32.34 ms -> [35, 31, 31, 31, 32, 31, 31, 31, 31, 31, 31, 31, 31, 31, 33, 32, 31, 31, 31, 31, 30, 32, 31, 31, 31, 31, 32, 30, 31, 31, 31, 30, 32, 31, 31, 31, 36, 31, 31, 31, 32, 30, 31, 32, 31, 31, 31, 31, 31, 32, 31, 31, 31, 31, 33, 32, 31, 32, 31, 31, 33, 31, 31, 31, 31, 31, 32, 31, 32, 31, 34, 38, 68, 42, 79, 33, 31, 31, 31, 31, 31, 30, 30, 30, 30, 31, 31, 31, 31, 32, 31, 32, 31, 31, 31, 32, 33, 33, 31, 31]
    C1.ToArray 56.32 ms -> [57, 56, 59, 54, 54, 55, 56, 57, 54, 54, 55, 55, 57, 56, 59, 57, 56, 58, 56, 56, 54, 56, 57, 55, 55, 55, 57, 58, 57, 58, 55, 55, 56, 55, 57, 56, 56, 59, 56, 56, 56, 56, 58, 56, 57, 56, 56, 57, 56, 55, 56, 56, 56, 59, 56, 56, 56, 55, 55, 54, 55, 54, 57, 56, 56, 56, 55, 55, 56, 56, 56, 59, 56, 56, 57, 56, 57, 56, 56, 56, 56, 62, 55, 56, 56, 56, 69, 57, 58, 56, 57, 58, 56, 57, 56, 56, 56, 56, 56, 56]
    S1.ToList 88.69 ms -> [96, 90, 90, 89, 91, 88, 89, 90, 96, 89, 89, 89, 90, 90, 90, 89, 90, 90, 89, 90, 89, 91, 89, 91, 89, 91, 89, 90, 90, 89, 87, 88, 87, 88, 87, 87, 87, 87, 88, 88, 87, 87, 89, 87, 87, 87, 91, 88, 87, 86, 89, 87, 90, 89, 89, 90, 89, 87, 87, 87, 86, 87, 88, 90, 88, 87, 87, 92, 87, 87, 88, 88, 88, 86, 86, 87, 88, 87, 87, 87, 89, 87, 89, 87, 90, 89, 89, 89, 91, 89, 90, 89, 90, 88, 90, 90, 90, 88, 89, 89]
    S1.ToArray 143.26 ms -> [130, 129, 130, 131, 133, 130, 131, 130, 135, 137, 130, 136, 132, 131, 130, 131, 132, 130, 132, 136, 130, 131, 157, 153, 194, 364, 176, 189, 203, 194, 189, 192, 183, 140, 142, 147, 145, 134, 159, 158, 142, 167, 130, 143, 145, 144, 160, 154, 156, 153, 153, 164, 142, 145, 137, 134, 145, 143, 142, 135, 133, 133, 135, 134, 134, 139, 139, 133, 134, 141, 133, 132, 133, 132, 133, 131, 135, 132, 133, 132, 128, 128, 130, 132, 129, 129, 129, 129, 129, 128, 134, 129, 129, 129, 129, 128, 128, 137, 130, 131]
    
    C2.ToList 3.25 ms -> [5, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 3, 3, 4, 4, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 4, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 3, 3, 4, 3, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3]
    C2.ToArray 3.37 ms -> [4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 4, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 4, 4, 3, 3, 4, 4, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 4, 4, 3, 4, 4, 3, 3, 4, 3, 3, 4, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 4, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3]
    S2.ToList 37.72 ms -> [38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 40, 38, 38, 39, 39, 38, 38, 38, 38, 37, 37, 37, 37, 39, 37, 37, 39, 38, 37, 37, 37, 37, 39, 38, 37, 37, 38, 37, 38, 37, 37, 38, 37, 37, 37, 38, 37, 37, 36, 37, 38, 37, 39, 37, 39, 38, 37, 38, 38, 38, 38, 38, 38, 37, 38, 38, 38, 38, 38, 37, 38, 37, 37, 38, 37, 37, 39, 41, 37, 38, 38, 37, 37, 37, 37, 38, 37, 37, 37, 40, 37, 37, 37, 37, 39, 38]
    S2.ToArray 38.86 ms -> [39, 37, 39, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 38, 38, 38, 39, 37, 38, 38, 38, 38, 38, 37, 37, 38, 37, 37, 38, 38, 40, 38, 38, 38, 38, 38, 39, 38, 38, 39, 38, 38, 39, 38, 38, 40, 38, 39, 38, 38, 39, 38, 38, 38, 38, 38, 39, 38, 38, 38, 39, 39, 37, 38, 38, 39, 71, 78, 37, 37, 37, 39, 38, 38, 39, 38, 38, 38, 38, 38, 39, 38, 38, 38, 39, 38, 38, 38]
    

    第2组:

    C.ToList 756.81 ms
    C.ToArray 774.21 ms
    S.ToList 709.7 ms
    S.ToArray 753.51 ms
    
    C1.ToList 32.06 ms
    C1.ToArray 56.58 ms
    S1.ToList 89.43 ms
    S1.ToArray 132.85 ms
    
    C2.ToList 3.45 ms
    C2.ToArray 3.36 ms
    S2.ToList 41.43 ms
    S2.ToArray 40.84 ms
    

    Group3:

    C.ToList 756.64 ms
    C.ToArray 771.56 ms
    S.ToList 705.42 ms
    S.ToArray 749.59 ms
    
    C1.ToList 31.45 ms
    C1.ToArray 57.03 ms
    S1.ToList 91.26 ms
    S1.ToArray 129.77 ms
    
    C2.ToList 3.26 ms
    C2.ToArray 3.29 ms
    S2.ToList 41.57 ms
    S2.ToArray 40.69 ms
    

    Group4:

    C.ToList 729.65 ms -> [749, 730, 721, 719, 723, 743, 721, 724, 727, 722, 716, 725, 723, 726, 718, 722, 731, 722, 723, 725, 723, 722, 728, 726, 728, 718, 726, 1088, 788, 737, 729, 710, 730, 728, 717, 723, 728, 721, 722, 728, 722, 736, 723, 729, 732, 724, 726, 727, 728, 728, 726, 726, 725, 727, 725, 728, 728, 718, 724, 725, 726, 724, 726, 729, 727, 722, 722, 725, 725, 728, 724, 727, 738, 717, 726, 723, 725, 725, 727, 724, 720, 726, 726, 723, 727, 730, 723, 721, 725, 727, 727, 733, 720, 722, 722, 725, 722, 725, 728, 726]
    C.ToArray 788.36 ms -> [748, 740, 742, 797, 1090, 774, 781, 787, 784, 786, 786, 782, 781, 781, 784, 783, 783, 781, 783, 787, 783, 784, 775, 789, 784, 785, 778, 774, 781, 783, 786, 781, 780, 788, 778, 785, 777, 781, 786, 782, 781, 787, 782, 787, 784, 773, 783, 782, 781, 777, 783, 781, 785, 788, 777, 776, 784, 784, 783, 789, 778, 781, 791, 768, 779, 783, 781, 787, 786, 781, 784, 781, 785, 781, 780, 809, 1155, 780, 790, 789, 783, 776, 785, 783, 786, 787, 782, 782, 787, 777, 779, 784, 783, 776, 786, 775, 782, 779, 784, 784]
    S.ToList 705.54 ms -> [690, 705, 709, 708, 702, 707, 703, 696, 703, 702, 700, 703, 700, 707, 705, 699, 697, 703, 695, 698, 707, 697, 711, 710, 699, 700, 708, 707, 693, 710, 704, 691, 702, 700, 703, 700, 705, 700, 703, 695, 709, 705, 698, 699, 709, 700, 699, 704, 691, 705, 703, 700, 708, 1048, 710, 706, 706, 692, 702, 705, 695, 701, 710, 697, 698, 706, 705, 707, 707, 695, 698, 704, 698, 699, 705, 698, 703, 702, 701, 697, 702, 702, 704, 703, 699, 707, 703, 705, 701, 717, 698, 695, 713, 696, 708, 705, 697, 699, 700, 698]
    S.ToArray 745.01 ms -> [751, 743, 727, 734, 736, 745, 739, 750, 739, 750, 758, 739, 744, 738, 730, 744, 745, 739, 744, 750, 733, 735, 743, 731, 749, 748, 727, 746, 749, 731, 737, 803, 1059, 756, 769, 748, 740, 745, 741, 746, 749, 732, 741, 742, 732, 744, 746, 737, 742, 739, 733, 744, 741, 729, 746, 760, 725, 741, 764, 739, 750, 751, 727, 745, 738, 727, 735, 741, 720, 736, 740, 733, 741, 746, 731, 749, 756, 740, 738, 736, 732, 741, 741, 733, 741, 744, 736, 742, 742, 735, 743, 746, 729, 748, 765, 743, 734, 742, 728, 749]
    
    C1.ToList 32.27 ms -> [36, 31, 31, 32, 31, 32, 31, 30, 32, 30, 30, 30, 34, 32, 31, 31, 31, 31, 31, 31, 31, 32, 38, 51, 68, 57, 35, 30, 31, 31, 30, 30, 33, 30, 31, 34, 31, 34, 32, 31, 31, 31, 31, 32, 30, 30, 31, 30, 31, 31, 32, 31, 31, 31, 32, 31, 31, 31, 32, 31, 33, 31, 31, 32, 30, 30, 30, 30, 30, 33, 30, 33, 32, 31, 30, 31, 31, 32, 32, 31, 35, 31, 34, 31, 31, 32, 31, 31, 32, 31, 32, 31, 31, 35, 31, 31, 31, 31, 31, 32]
    C1.ToArray 56.72 ms -> [58, 56, 57, 57, 59, 58, 58, 57, 56, 59, 57, 55, 55, 54, 56, 55, 56, 56, 57, 59, 56, 55, 58, 56, 55, 55, 55, 55, 58, 58, 55, 57, 57, 56, 57, 57, 57, 57, 59, 59, 56, 57, 56, 57, 57, 56, 57, 59, 58, 56, 57, 57, 57, 58, 56, 56, 59, 56, 59, 57, 57, 57, 57, 59, 57, 56, 57, 56, 58, 56, 57, 56, 57, 59, 55, 58, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 56, 56, 57, 56, 56, 57, 58, 57, 57, 57, 57, 57]
    S1.ToList 90.72 ms -> [95, 90, 90, 89, 89, 89, 91, 89, 89, 87, 91, 89, 89, 89, 91, 89, 89, 89, 90, 89, 89, 90, 88, 89, 88, 90, 89, 90, 89, 89, 90, 90, 89, 89, 90, 91, 89, 91, 89, 90, 89, 89, 90, 91, 89, 89, 89, 89, 89, 89, 90, 89, 89, 89, 90, 89, 90, 89, 91, 89, 90, 89, 90, 89, 90, 89, 96, 89, 90, 89, 89, 89, 89, 89, 90, 89, 89, 89, 90, 87, 89, 90, 90, 91, 89, 91, 89, 89, 90, 91, 90, 89, 93, 144, 149, 90, 90, 89, 89, 89]
    S1.ToArray 131.4 ms -> [130, 128, 127, 134, 129, 129, 130, 136, 131, 130, 132, 132, 133, 131, 132, 131, 133, 132, 130, 131, 132, 131, 130, 133, 133, 130, 130, 131, 131, 131, 132, 134, 131, 131, 132, 131, 132, 131, 134, 131, 131, 130, 131, 131, 130, 132, 129, 131, 131, 131, 132, 131, 133, 134, 131, 131, 132, 132, 131, 133, 131, 131, 130, 133, 131, 130, 134, 132, 131, 132, 132, 131, 131, 134, 131, 131, 132, 132, 131, 130, 138, 130, 130, 131, 132, 132, 130, 134, 131, 131, 132, 131, 130, 132, 133, 131, 131, 131, 130, 131]
    
    C2.ToList 3.21 ms -> [4, 3, 3, 3, 4, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3, 3, 3, 4, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 4, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 4, 3, 3, 3]
    C2.ToArray 3.22 ms -> [4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3, 4, 3, 4, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 4, 3, 4, 3, 3, 3, 3, 3, 4, 3, 3, 3, 4, 3, 4, 3, 3, 3, 3, 4]
    S2.ToList 41.46 ms -> [42, 40, 41, 40, 42, 40, 40, 40, 40, 40, 40, 40, 40, 41, 40, 40, 41, 40, 40, 40, 39, 41, 41, 39, 40, 40, 43, 40, 39, 40, 40, 40, 40, 40, 40, 41, 40, 40, 40, 43, 40, 43, 75, 76, 47, 39, 40, 40, 40, 40, 42, 40, 41, 40, 40, 40, 44, 41, 40, 42, 42, 40, 41, 41, 41, 41, 41, 40, 41, 41, 41, 41, 42, 41, 40, 41, 41, 42, 42, 41, 40, 41, 41, 41, 41, 41, 40, 42, 40, 42, 41, 41, 41, 43, 41, 41, 41, 41, 42, 41]
    S2.ToArray 41.14 ms -> [42, 41, 41, 40, 40, 40, 40, 41, 41, 42, 41, 42, 41, 41, 41, 42, 41, 41, 42, 41, 41, 41, 41, 41, 42, 40, 41, 40, 42, 40, 42, 41, 40, 42, 41, 41, 43, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 40, 40, 41, 41, 41, 40, 42, 41, 41, 41, 41, 41, 40, 41, 41, 42, 41, 41, 41, 42, 41, 41, 41, 41, 41, 41, 42, 42, 42, 41, 45, 46, 41, 40, 41, 41, 42, 41, 41, 41, 41, 41, 41, 40, 41, 43, 40, 40, 40, 40, 43, 41]
    

    第5组:

    C.ToList 757.06 ms -> [770, 752, 752, 751, 778, 763, 761, 763, 747, 758, 748, 747, 754, 749, 752, 753, 756, 762, 750, 753, 756, 749, 755, 757, 755, 756, 755, 744, 753, 758, 747, 751, 759, 751, 761, 755, 746, 752, 752, 749, 746, 752, 753, 755, 752, 755, 754, 754, 966, 937, 749, 759, 748, 747, 754, 749, 755, 750, 746, 754, 757, 752, 753, 745, 758, 755, 761, 753, 751, 755, 755, 752, 746, 756, 755, 746, 742, 751, 751, 749, 752, 751, 756, 756, 755, 742, 749, 754, 749, 756, 753, 751, 754, 752, 751, 754, 753, 749, 755, 756]
    C.ToArray 772.8 ms -> [766, 772, 755, 763, 758, 767, 763, 762, 761, 768, 769, 763, 770, 757, 765, 760, 766, 759, 764, 761, 760, 777, 1102, 881, 759, 765, 758, 762, 772, 761, 758, 757, 765, 769, 769, 761, 762, 762, 763, 760, 770, 764, 760, 768, 758, 766, 763, 770, 769, 761, 764, 761, 761, 767, 761, 762, 764, 757, 765, 766, 767, 771, 753, 762, 769, 768, 759, 764, 764, 760, 763, 763, 763, 763, 763, 767, 761, 771, 760, 765, 760, 758, 768, 770, 751, 771, 767, 771, 765, 763, 760, 765, 765, 769, 767, 767, 1193, 774, 767, 764]
    S.ToList 704.73 ms -> [682, 708, 705, 699, 705, 704, 695, 703, 702, 699, 701, 708, 699, 702, 703, 701, 701, 699, 701, 707, 707, 700, 701, 705, 700, 697, 706, 702, 701, 706, 699, 692, 702, 697, 707, 704, 697, 698, 699, 699, 702, 703, 698, 697, 702, 703, 702, 704, 694, 697, 707, 695, 711, 710, 700, 693, 703, 699, 699, 706, 698, 701, 703, 704, 698, 706, 700, 704, 701, 699, 702, 705, 694, 698, 709, 736, 1053, 704, 694, 700, 698, 696, 701, 700, 700, 706, 706, 692, 698, 707, 703, 695, 703, 699, 694, 708, 695, 694, 706, 695]
    S.ToArray 744.17 ms -> [746, 740, 725, 740, 739, 731, 746, 760, 735, 738, 740, 734, 744, 748, 737, 744, 745, 727, 736, 738, 728, 743, 745, 735, 748, 760, 739, 748, 762, 742, 741, 747, 733, 746, 758, 742, 742, 741, 724, 744, 747, 727, 740, 740, 729, 742, 757, 741, 740, 742, 726, 739, 746, 1133, 749, 737, 730, 740, 747, 733, 747, 752, 731, 747, 742, 730, 741, 749, 731, 749, 743, 730, 747, 742, 731, 737, 745, 734, 739, 735, 727, 743, 752, 731, 744, 742, 729, 740, 746, 731, 739, 746, 733, 745, 743, 733, 739, 742, 727, 737]
    
    C1.ToList 31.71 ms -> [35, 32, 32, 30, 31, 33, 31, 32, 32, 31, 31, 32, 32, 33, 32, 31, 31, 32, 31, 32, 32, 32, 31, 32, 33, 32, 31, 31, 31, 32, 31, 34, 31, 31, 32, 33, 32, 32, 31, 32, 34, 32, 31, 32, 33, 31, 32, 32, 31, 32, 32, 32, 32, 32, 32, 31, 31, 32, 31, 33, 30, 31, 32, 30, 30, 33, 32, 32, 34, 31, 31, 31, 31, 32, 31, 31, 31, 31, 32, 31, 31, 33, 31, 32, 32, 32, 33, 32, 31, 31, 31, 31, 31, 32, 32, 33, 32, 31, 31, 32]
    C1.ToArray 59.53 ms -> [63, 57, 58, 58, 57, 59, 59, 57, 60, 131, 127, 67, 58, 56, 59, 56, 57, 58, 58, 58, 57, 59, 60, 57, 57, 59, 60, 57, 57, 57, 58, 58, 58, 58, 57, 57, 61, 57, 58, 57, 57, 57, 57, 57, 58, 58, 58, 58, 57, 58, 59, 57, 58, 57, 57, 59, 58, 58, 59, 57, 59, 57, 56, 56, 59, 56, 56, 59, 57, 58, 58, 58, 57, 58, 59, 59, 58, 57, 58, 62, 65, 57, 57, 57, 58, 60, 59, 58, 59, 57, 58, 57, 58, 59, 58, 58, 58, 59, 60, 58]
    S1.ToList 82.78 ms -> [87, 82, 83, 83, 82, 82, 83, 84, 82, 83, 84, 84, 84, 82, 82, 84, 82, 84, 83, 84, 82, 82, 82, 81, 83, 83, 83, 84, 84, 82, 82, 83, 83, 83, 82, 83, 85, 83, 82, 82, 84, 82, 82, 83, 83, 83, 82, 82, 82, 83, 82, 83, 82, 84, 82, 83, 82, 83, 82, 82, 82, 84, 82, 83, 82, 82, 86, 83, 83, 82, 83, 83, 83, 82, 84, 82, 83, 81, 82, 82, 82, 82, 83, 83, 83, 82, 83, 84, 83, 82, 83, 83, 83, 82, 83, 84, 82, 82, 83, 83]
    S1.ToArray 122.3 ms -> [122, 119, 119, 120, 119, 120, 120, 121, 119, 119, 122, 120, 120, 120, 122, 120, 123, 120, 120, 120, 121, 123, 120, 120, 120, 121, 120, 121, 122, 120, 123, 119, 121, 118, 121, 120, 120, 120, 119, 124, 119, 121, 119, 120, 120, 120, 120, 120, 122, 121, 123, 230, 203, 123, 119, 119, 122, 119, 120, 120, 120, 122, 120, 121, 120, 121, 120, 121, 120, 121, 120, 120, 120, 121, 122, 121, 123, 119, 119, 119, 119, 121, 120, 120, 120, 122, 121, 122, 119, 120, 120, 121, 121, 120, 121, 120, 121, 118, 118, 118]
    
    C2.ToList 3.43 ms -> [5, 3, 4, 4, 4, 3, 4, 4, 4, 4, 4, 3, 3, 3, 4, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 4, 3, 3, 3, 3, 4, 3, 3, 3, 4, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 6, 4, 4, 3, 3, 4, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 4, 3, 4, 4, 4, 3, 4, 4, 3, 4, 4, 4, 4, 4, 4, 3, 3, 3, 4, 4, 3, 3, 3, 3]
    C2.ToArray 3.48 ms -> [3, 3, 3, 3, 4, 4, 3, 4, 4, 4, 3, 4, 3, 3, 4, 3, 3, 4, 3, 4, 3, 3, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 4, 3, 3, 4, 3, 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 4, 3, 3, 4, 3, 3, 4, 3, 3, 4, 4, 3, 3, 4, 3, 4, 4, 3, 4, 4, 4, 4, 4, 3, 3, 3, 4, 4, 3, 4, 4, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4, 3]
    S2.ToList 41.47 ms -> [41, 41, 49, 67, 82, 41, 41, 40, 40, 40, 40, 40, 41, 40, 40, 40, 40, 40, 41, 40, 42, 42, 40, 40, 41, 41, 41, 40, 41, 40, 41, 40, 41, 40, 42, 41, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 42, 41, 41, 41, 42, 40, 41, 40, 40, 40, 42, 40, 41, 42, 41, 42, 41, 42, 40, 41, 41, 41, 41, 41, 41, 41, 41, 40, 41, 40, 41, 41, 41, 40, 41, 41, 40, 40, 41, 41, 41, 41, 41, 43, 40, 40, 41, 42, 41]
    S2.ToArray 40.62 ms -> [42, 41, 44, 40, 40, 40, 40, 41, 41, 40, 41, 41, 41, 40, 41, 41, 40, 41, 41, 40, 41, 40, 40, 41, 42, 41, 41, 41, 40, 40, 40, 40, 40, 41, 41, 42, 40, 41, 41, 41, 41, 41, 40, 42, 40, 40, 41, 41, 41, 40, 41, 40, 40, 40, 40, 40, 41, 40, 40, 41, 40, 40, 40, 40, 41, 40, 41, 41, 41, 40, 41, 41, 40, 41, 40, 41, 42, 40, 41, 41, 42, 41, 41, 40, 41, 40, 41, 40, 41, 41, 40, 40, 40, 41, 41, 40, 40, 40, 40, 40]
    

    由于stackoverflow对答案字符数量的限制,因此省略了Group2和Group3的样本列表 .

    如您所见,在大多数情况下使用 ToListToArry 并不重要 .

    在处理运行时计算的 IEnumerable<T> 对象时,如果计算带来的负载比 ToListToArray 的内存分配和复制操作重,则差异无关紧要( C.ToList vs C.ToArrayS.ToList vs S.ToArray ) .

    只能在非运行时计算的 IEnumerable<T> 对象( C1.ToList vs C1.ToArrayS1.ToList vs S1.ToArray )上观察到差异 . 但绝对差异(<60ms)仍然可以接受一百万个小物件 IEnumerable<T> . 实际上,差异是由 Enumerator<T>Enumerator<T> 的实施决定的 . 所以,如果你的程序真的非常敏感,你必须 profile, profile, profile !最后你可能会发现瓶颈不是 ToListToArray ,而是枚举器的细节 .

    并且, C2.ToList vs C2.ToArrayS2.ToList vs S2.ToArray 的结果表明,在非运行时计算的 ICollection<T> 对象上,您实际上不需要关心 ToListToArray .

    当然,这只是我机器上的结果,这些操作在不同机器上的实际花费时间会不一样,你可以使用上面的代码在你的机器上找到 .

    您需要做出选择的唯一原因是,您对 List<T>T[] 有特定需求,如@Jeppe Stig Nielsen的答案所述 .

  • 19

    对于有兴趣在另一个Linq-to-sql中使用此结果的人

    from q in context.MyTable
    where myListOrArray.Contains(q.someID)
    select q;
    

    那么无论是否为myListOrArray使用List或Array,生成的SQL都是相同的 . 现在我知道有些人可能会问为什么甚至在这个语句之前进行枚举,但是从IQueryable vs(List或Array)生成的SQL之间存在差异 .

  • 1

    ToListAsync<T>() 是首选 .

    在实体框架6中,两种方法最终都调用相同的内部方法,但 ToArrayAsync<T>() 最后调用 list.ToArray() ,这实现为

    T[] array = new T[_size];
    Array.Copy(_items, 0, array, 0, _size);
    return array;
    

    所以 ToArrayAsync<T>() 有一些开销,因此 ToListAsync<T>() 是首选 .

相关问题