在 C# 中用零初始化一个浮点列表

axc*_*tor 3 c# initialization list space-efficiency

我想用零( 0.0 )启动 N 个对象的列表。我想这样做:

var TempList = new List<float>(new float[(int)(N)]);
Run Code Online (Sandbox Code Playgroud)

有没有更好(更有效)的方法来做到这一点?

Mat*_*son 6

您当前的解决方案创建一个数组,其唯一目的是用零初始化一个列表,然后将该数组扔掉。这可能看起来效率不高。然而,正如我们将看到的,它实际上非常有效!

这是一个不创建中间数组的方法:

int n = 100;

var list = new List<float>(n);

for (int i = 0; i < n; ++i)
    list.Add(0f);
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用Enumerable.Repeat()提供0f“n”次,如下所示:

var list = new List<float>(n);
list.AddRange(Enumerable.Repeat(0f, n));
Run Code Online (Sandbox Code Playgroud)

但结果证明这两种方法都比较慢!

这是一个小测试应用程序来做一些计时。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace Demo
{
    public class Program
    {
        private static void Main()
        {
            var sw = new Stopwatch();

            int n = 1024*1024*16;
            int count = 10;
            int dummy = 0;

            for (int trial = 0; trial < 4; ++trial)
            {
                sw.Restart();

                for (int i = 0; i < count; ++i)
                    dummy += method1(n).Count;

                Console.WriteLine("Enumerable.Repeat() took " + sw.Elapsed);
                sw.Restart();

                for (int i = 0; i < count; ++i)
                    dummy += method2(n).Count;

                Console.WriteLine("list.Add() took " + sw.Elapsed);
                sw.Restart();

                for (int i = 0; i < count; ++i)
                    dummy += method3(n).Count;

                Console.WriteLine("(new float[n]) took " + sw.Elapsed);

                Console.WriteLine("\n");
            }
        }

        private static List<float> method1(int n)
        {
            var list = new List<float>(n);
            list.AddRange(Enumerable.Repeat(0f, n));
            return list;
        }

        private static List<float> method2(int n)
        {
            var list = new List<float>(n);

            for (int i = 0; i < n; ++i)
                list.Add(0f);

            return list;
        }

        private static List<float> method3(int n)
        {
            return new List<float>(new float[n]);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的 RELEASE 构建结果:

Enumerable.Repeat() took 00:00:02.9508207
list.Add() took 00:00:01.1986594
(new float[n]) took 00:00:00.5318123
Run Code Online (Sandbox Code Playgroud)

所以事实证明,创建一个中间数组要快得多。但是,请注意,此测试代码存在缺陷,因为它没有考虑由分配中间数组(很难正确计时)引起的垃圾收集开销。

最后,有一种非常邪恶、令人讨厌的方法可以使用反射来优化它。但这是脆弱的,将来可能无法工作,并且永远不应该在生产代码中使用。

我在这里提出它只是出于好奇:

private static List<float> method4(int n)
{
    var list = new List<float>(n);
    list.GetType().GetField("_size", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(list, n);
    return list;
}
Run Code Online (Sandbox Code Playgroud)

与下一个最快的方法需要半秒相比,这样做可以将时间减少到不到十分之一秒。但不要这样做。