在c#中初始化带有零的浮点数列表

本文关键字:浮点数 列表 初始化 | 更新日期: 2023-09-27 18:02:57

我想初始化一个包含N个0(0.0)对象的列表。我想这样做:

var TempList = new List<float>(new float[(int)(N)]);
有没有更好(更有效)的方法来做那件事?

在c#中初始化带有零的浮点数列表

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

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

int n = 100;
var list = new List<float>(n);
for (int i = 0; i < n; ++i)
    list.Add(0f);

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

var list = new List<float>(n);
list.AddRange(Enumerable.Repeat(0f, n));

但是这两种方法都比较慢!

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

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]);
        }
    }
}

这是我发布版本的结果:

Enumerable.Repeat() took 00:00:02.9508207
list.Add() took 00:00:01.1986594
(new float[n]) took 00:00:00.5318123

创建一个中间数组要快得多。但是,请注意,这个测试代码是有缺陷的,因为它没有考虑到分配中间数组引起的垃圾收集开销(这很难正确地计时)。

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

我把它放在这里只是为了好奇:

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;
}

这样做可以将时间减少到不到十分之一秒,而第二快的方法需要半秒。但千万别这么做。

怎么了

float[] A = new float[N];

List<float> A = new List<float>(N);

注意,试图对编译器进行微管理并不是优化。从你想要的最干净的代码开始,让编译器做它的事情。

编辑1 List<float>的解决方案产生一个空列表,只在内部初始化N项。所以我们可以用一些反射

来欺骗它
    static void Main(string[] args)
    {
        int N=100;
        float[] array = new float[N];
        List<float> list=new List<float>(N);
        var size=typeof(List<float>).GetField("_size", BindingFlags.Instance|BindingFlags.NonPublic);
        size.SetValue(list, N);
        // Now list has 100 zero items
    }

为什么不呢:

var itemsWithZeros = new float[length];