Initiate a float list with zeros in C#

10,329

Your current solution creates an array with the sole purpose of initialising a list with zeros, and then throws that array away. This might appear to be not efficient. However, as we shall see, it is in fact very efficient!

Here's a method that doesn't create an intermediary array:

int n = 100;

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

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

Alternatively, you can use Enumerable.Repeat() to provide 0f "n" times, like so:

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

But both these methods turn out to be a slower!

Here's a little test app to do some timings.

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

Here's my results for a RELEASE build:

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

So it turns out that creating an intermediary array is quite a lot faster. However, be aware that this testing code is flawed because it doesn't account for garbage collection overhead caused by allocating the intermediary array (which is very hard to time properly).

Finally, there is a REALLY EVIL, NASTY way you can optimise this using reflection. But this is brittle, will probably fail to work in the future, and should never, ever be used in production code.

I present it here only as a curiosity:

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

Doing this reduces the time to less than a tenth of a second, compared to the next fastest method which takes half a second. But don't do it.

Share:
10,329
axcelenator
Author by

axcelenator

Updated on June 04, 2022

Comments

  • axcelenator
    axcelenator almost 2 years

    I want to initiate a list of N objects with zeros( 0.0 ) . I thought of doing it like that:

    var TempList = new List<float>(new float[(int)(N)]);
    

    Is there any better(more efficeint) way to do that?