Jak wypełnić / utworzyć instancję tablicy C# z pojedynczą wartością?

Wiem, że instancyjne tablice typów wartości w C# są automatycznie wypełniane wartością domyślną typu (np. false dla bool, 0 dla int, itd.).

Czy istnieje sposób na automatyczne wypełnienie tablicy wartością początkową, która nie jest domyślna? Albo przy tworzeniu, albo po wbudowanej metodzie (jak tablice Javy).fill () )? Powiedzmy, że chciałem tablicy logicznej, która domyślnie była prawdziwa, zamiast false. Czy istnieje wbudowany sposób, aby to zrobić, czy po prostu trzeba iterować przez tablicę za pomocą pętli for?

 // Example pseudo-code:
 bool[] abValues = new[1000000];
 Array.Populate(abValues, true);

 // Currently how I'm handling this:
 bool[] abValues = new[1000000];
 for (int i = 0; i < 1000000; i++)
 {
     abValues[i] = true;
 }

Konieczność iteracji przez tablicę i "resetowania" każdej wartości do wartości true wydaje się nieefektywna. Czy w ogóle jest w pobliżu tego? Może przerzucając wszystkie wartości?

Po wpisaniu tego pytania i zastanowieniu się nad nim, domyślam się, że domyślne wartości są po prostu wynikiem tego, jak C# radzi sobie z alokacją pamięci tych obiektów za kulisami, więc domyślam się, że prawdopodobnie nie jest to możliwe. Ale i tak chciałbym wiedzieć dla jasne!

Author: Nayuki, 0000-00-00

10 answers

Nie znam metody framework, ale możesz napisać szybki helper, który zrobi to za Ciebie.

public static void Populate<T>(this T[] arr, T value ) {
  for ( int i = 0; i < arr.Length;i++ ) {
    arr[i] = value;
  }
}
 114
Author: JaredPar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-23 14:07:29
Enumerable.Repeat(true, 1000000).ToArray();
 160
Author: Rony,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-18 17:29:41

Utwórz nową tablicę z tysiącem true wartości:

var items = Enumerable.Repeat<bool>(true, 1000).ToArray();  // Or ToList(), etc.

Podobnie można wygenerować sekwencje całkowite:

var items = Enumerable.Range(0, 1000).ToArray();  // 0..999
 50
Author: bytebender,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-31 10:14:58

Dla dużych tablic lub tablic o zmiennej wielkości powinieneś prawdopodobnie użyć:

Enumerable.Repeat(true, 1000000).ToArray();

Dla małej tablicy można użyć składni inicjalizacji kolekcji w C # 3:

bool[] vals = new bool[]{ false, false, false, false, false, false, false };

Zaletą składni inicjalizacji kolekcji jest to, że nie musisz używać tej samej wartości w każdym slocie i możesz używać wyrażeń lub funkcji do inicjalizacji slotu. Ponadto, myślę, że można uniknąć kosztów inicjalizacji gniazda tablicy do wartości domyślnej. Na przykład:

bool[] vals = new bool[]{ false, true, false, !(a ||b) && c, SomeBoolMethod() };
 21
Author: LBushkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-18 17:39:23

Jeśli Twoja tablica jest tak duża, powinieneś użyć BitArray. Używa 1 bit dla każdego boola zamiast bajtu (jak w tablicy Booli) można również ustawić wszystkie bity na true za pomocą operatorów bitowych. Lub po prostu zainicjować na true. Jeśli musisz to zrobić tylko raz, będzie to kosztować tylko więcej.

System.Collections.BitArray falses = new System.Collections.BitArray(100000, false);
System.Collections.BitArray trues = new System.Collections.BitArray(100000, true);

// Now both contain only true values.
falses.And(trues);
 20
Author: MrFox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-24 07:58:15

Cóż po trochę więcej googlowania i czytania znalazłem to:

bool[] bPrimes = new bool[1000000];
bPrimes = Array.ConvertAll<bool, bool>(bPrimes, b=> b=true);
Co z pewnością jest bliższe temu, czego szukam. Ale nie jestem pewien, czy to jest lepsze niż iteracja przez oryginalną tablicę w pętli for i po prostu zmiana wartości. Po szybkim teście w rzeczywistości wydaje się wolniejszy o współczynnik 5. Więc to nie jest dobre rozwiązanie!
 8
Author: patjbs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-18 17:35:59

Niestety nie wydaje mi się, aby istniał bezpośredni sposób, jednak myślę, że możesz napisać metodę rozszerzenia dla klasy array, aby to zrobić

class Program
{
    static void Main(string[] args)
    {
        int[] arr = new int[1000];
        arr.Init(10);
        Array.ForEach(arr, Console.WriteLine);
    }
}

public static class ArrayExtensions
{
    public static void Init<T>(this T[] array, T defaultVaue)
    {
        if (array == null)
            return;
        for (int i = 0; i < array.Length; i++)
        {
            array[i] = defaultVaue;
        }
    }
}
 7
Author: bashmohandes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-18 17:29:16

Co z równoległą implementacją

public static void InitializeArray<T>(T[] array, T value)
{
    var cores = Environment.ProcessorCount;

    ArraySegment<T>[] segments = new ArraySegment<T>[cores];

    var step = array.Length / cores;
    for (int i = 0; i < cores; i++)
    {
        segments[i] = new ArraySegment<T>(array, i * step, step);
    }
    var remaining = array.Length % cores;
    if (remaining != 0)
    {
        var lastIndex = segments.Length - 1;
        segments[lastIndex] = new ArraySegment<T>(array, lastIndex * step, array.Length - (lastIndex * step));
    }

    var initializers = new Task[cores];
    for (int i = 0; i < cores; i++)
    {
        var index = i;
        var t = new Task(() =>
        {
            var s = segments[index];
            for (int j = 0; j < s.Count; j++)
            {
                array[j + s.Offset] = value;
            }
        });
        initializers[i] = t;
        t.Start();
    }

    Task.WaitAll(initializers);
}

Podczas inicjalizacji tablicy nie widać mocy tego kodu, ale myślę, że zdecydowanie powinieneś zapomnieć o" czystym " for.

 6
Author: Petar Petrov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-24 08:44:50

Poniższy kod łączy prostą iterację dla małych kopii i tablicy.Kopia dla dużych kopii

    public static void Populate<T>( T[] array, int startIndex, int count, T value ) {
        if ( array == null ) {
            throw new ArgumentNullException( "array" );
        }
        if ( (uint)startIndex >= array.Length ) {
            throw new ArgumentOutOfRangeException( "startIndex", "" );
        }
        if ( count < 0 || ( (uint)( startIndex + count ) > array.Length ) ) {
            throw new ArgumentOutOfRangeException( "count", "" );
        }
        const int Gap = 16;
        int i = startIndex;

        if ( count <= Gap * 2 ) {
            while ( count > 0 ) {
                array[ i ] = value;
                count--;
                i++;
            }
            return;
        }
        int aval = Gap;
        count -= Gap;

        do {
            array[ i ] = value;
            i++;
            --aval;
        } while ( aval > 0 );

        aval = Gap;
        while ( true ) {
            Array.Copy( array, startIndex, array, i, aval );
            i += aval;
            count -= aval;
            aval *= 2;
            if ( count <= aval ) {
                Array.Copy( array, startIndex, array, i, count );
                break;
            }
        }
    }

Wzorce dla różnej długości tablicy przy użyciu tablicy int[] to:

         2 Iterate:     1981 Populate:     2845
         4 Iterate:     2678 Populate:     3915
         8 Iterate:     4026 Populate:     6592
        16 Iterate:     6825 Populate:    10269
        32 Iterate:    16766 Populate:    18786
        64 Iterate:    27120 Populate:    35187
       128 Iterate:    49769 Populate:    53133
       256 Iterate:   100099 Populate:    71709
       512 Iterate:   184722 Populate:   107933
      1024 Iterate:   363727 Populate:   126389
      2048 Iterate:   710963 Populate:   220152
      4096 Iterate:  1419732 Populate:   291860
      8192 Iterate:  2854372 Populate:   685834
     16384 Iterate:  5703108 Populate:  1444185
     32768 Iterate: 11396999 Populate:  3210109

Pierwsze kolumny to rozmiar tablicy, po której następuje czas kopiowania za pomocą prostej iteracji (implementacja @ JaredPared ). Czas tej metody jest po tym. Są to benchmarki wykorzystujące tablicę struktury czterech liczb całkowitych

         2 Iterate:     2473 Populate:     4589
         4 Iterate:     3966 Populate:     6081
         8 Iterate:     7326 Populate:     9050
        16 Iterate:    14606 Populate:    16114
        32 Iterate:    29170 Populate:    31473
        64 Iterate:    57117 Populate:    52079
       128 Iterate:   112927 Populate:    75503
       256 Iterate:   226767 Populate:   133276
       512 Iterate:   447424 Populate:   165912
      1024 Iterate:   890158 Populate:   367087
      2048 Iterate:  1786918 Populate:   492909
      4096 Iterate:  3570919 Populate:  1623861
      8192 Iterate:  7136554 Populate:  2857678
     16384 Iterate: 14258354 Populate:  6437759
     32768 Iterate: 28351852 Populate: 12843259
 5
Author: Panos Theof,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-01 12:49:48

Lub... możesz po prostu użyć odwróconej logiki. Niech false oznacza true i odwrotnie.

Przykład kodu

// bool[] isVisible = Enumerable.Repeat(true, 1000000).ToArray();
bool[] isHidden = new bool[1000000]; // Crazy-fast initialization!

// if (isVisible.All(v => v))
if (isHidden.All(v => !v))
{
    // Do stuff!
}
 5
Author: l33t,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-26 09:42:44