Bagaimana cara mengisi / membuat array C # dengan nilai tunggal?

205

Saya tahu bahwa array instantiated dari tipe nilai dalam C # secara otomatis diisi dengan nilai default tipe (misalnya false untuk bool, 0 untuk int, dll).

Apakah ada cara untuk mengisi array secara otomatis dengan nilai seed yang bukan default? Baik pada pembuatan atau metode bawaan sesudahnya (seperti Java's Arrays.fill () )? Katakanlah saya ingin array boolean yang benar secara default, bukan false. Apakah ada cara built-in untuk melakukan ini, atau Anda hanya perlu beralih melalui array dengan for 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;
 }

Harus beralih melalui array dan "mengatur ulang" setiap nilai ke true tampaknya tidak efisien. Apakah ada masalah di sekitar ini? Mungkin dengan membalik semua nilai?

Setelah mengetik pertanyaan ini dan memikirkannya, saya menduga bahwa nilai default hanyalah hasil dari bagaimana C # menangani alokasi memori objek-objek ini di belakang layar, jadi saya membayangkan mungkin tidak mungkin untuk melakukan ini. Tapi saya masih ingin tahu pasti!

patjb
sumber
Saya biasanya mengubah nama dari is_found ke is_still_hiding. Suka jawabannya, saya perlu melakukan hal yang sama untuk array int dalam kasus uji. (pertanyaan bagus)
ctrl-alt-delor

Jawaban:

146

Tidak tahu metode kerangka kerja tetapi Anda bisa menulis bantuan cepat untuk melakukannya untuk Anda.

public static void Populate<T>(this T[] arr, T value ) {
  for ( int i = 0; i < arr.Length;i++ ) {
    arr[i] = value;
  }
}
JaredPar
sumber
3
Lebih suka ++ i daripada i ++ jika Anda tidak membutuhkan salinannya.
void.pointer
24
i ++ menyalin saya, menambah saya, dan mengembalikan nilai aslinya. ++ saya baru saja mengembalikan nilai yang bertambah. Karena itu ++ i lebih cepat, yang bisa jadi signifikan dalam loop besar seperti yang kita bicarakan di sini.
tenpn
57
@RobertDailey: Itu adalah pengoptimalan kompiler, dan tidak lagi benar. Saya baru saja menguji untuk memverifikasi keyakinan saya: Jika nilai kembali i ++ tidak digunakan untuk apa pun, maka kompiler akan mengkompilasinya sebagai ++ saya secara otomatis untuk Anda. Juga, bahkan ketika saya menggunakan nilai pengembalian, perbedaan kinerja sangat kecil sehingga saya perlu membuat case yang ekstrem untuk mengukurnya. Bahkan kemudian, itu menghasilkan runtime hanya beberapa persen berbeda.
Edward Ned Harvey
8
Saya menulis metode ekstensi seperti ini tapi saya mengembalikannya ke array asli untuk memungkinkan metode chaining seperti:int[] arr = new int[16].Populate(-1);
Gutblender
2
Ubah voidke T[]dan kemudian Anda dapat melakukanvar a = new int[100].Polupate(1)
orad
198
Enumerable.Repeat(true, 1000000).ToArray();
Rony
sumber
70
Meskipun ini berfungsi, itu bukan solusi yang baik karena sangat lambat; itu sekitar 4 kali lebih lambat daripada iterasi dengan for loop sebenarnya.
patjbs
4
ya itu benar, ketika kami menganggap kinerja untuk loop lebih cepat
Rony
6
Untuk melihat beberapa tolok ukur nyata, lihat C # Initialize Array .
theknut
4
Enumerable.ToArraytidak tahu ukuran urutan enumerable, sehingga harus menebak ukuran array. Itu berarti Anda akan mendapatkan alokasi array setiap kali ToArraybuffer terlampaui, ditambah satu alokasi lagi di akhir trim. Ada juga overhead yang terlibat dengan objek enumerable.
Edward Brey
5
Hanya sebuah catatan, bahwa dengan tipe referensi ini akan mengisi seluruh array dengan semua referensi ke objek tunggal yang sama. Jika ini bukan yang Anda inginkan dan Anda benar-benar ingin membuat objek yang berbeda untuk setiap item array, lihat stackoverflow.com/a/44937053/23715 .
Alex Che
74

Buat array baru dengan seribu truenilai:

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

Demikian pula, Anda dapat menghasilkan urutan integer:

var items = Enumerable.Range(0, 1000).ToArray();  // 0..999
bytebender
sumber
8
Tidak buruk, tapi masih lebih lambat dari untuk loop sekitar faktor 4x
patjbs
1
patjb dalam teori di masa depan Enumerable.Repeat akan melakukan lebih cepat karena akan menggunakan implementasi paralel.
Petar Petrov
1
@PetarPetrov Ini tidak akan pernah terjadi karena meronta-ronta cache. Saya cukup yakin bahwa karena sifat cache CPU, melakukan pekerjaan secara paralel pada satu array akan selalu lebih lambat tidak peduli apa karena komputer mengharapkan kerja sinkron dan memuat data dengan tepat.
TernaryTopiary
pesimisasi yang dimaksudkan! = kurangnya optimasi prematur.
Denis Gladkiy
24

Untuk array atau array besar yang akan berukuran variabel, Anda mungkin harus menggunakan:

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

Untuk array kecil Anda dapat menggunakan sintaks inisialisasi koleksi di C # 3:

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

Manfaat sintaks inisialisasi koleksi, adalah Anda tidak harus menggunakan nilai yang sama di setiap slot dan Anda dapat menggunakan ekspresi atau fungsi untuk menginisialisasi slot. Juga, saya pikir Anda menghindari biaya inisialisasi slot array ke nilai default. Jadi, misalnya:

bool[] vals = new bool[]{ false, true, false, !(a ||b) && c, SomeBoolMethod() };
LBushkin
sumber
Dan untuk menginisialisasi array float []:float[] AlzCalDefault = new float[] {(float) 0.5, 18, 500, 1, 0};
Jim Lahman
Inisialisasi FWIW dari sebuah array dapat dilakukan dalam versi C # seperti:bool[] vals = { false, true, false, !(a || b) && c, SomeBoolMethod() };
Peter van der Heijden
24

Jika array Anda terlalu besar, Anda harus menggunakan BitArray. Ini menggunakan 1 bit untuk setiap bool, bukan byte (seperti dalam array bools) juga Anda dapat mengatur semua bit menjadi true dengan operator bit. Atau hanya menginisialisasi pada true. Jika Anda hanya perlu melakukannya sekali, itu hanya akan memakan biaya lebih banyak.

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);
MrFox
sumber
17

Anda dapat menggunakan Array.Fill.NET Core 2.0+ dan .NET Standard 2.1+.

juFo
sumber
Luar biasa! Padahal perlu disadari bahwa itu adalah metode yang relatif baru. Ini tersedia di .NET Core 2.0+ dan .NET Standard 2.1, tetapi secara khusus tidak ada dalam versi .NET Framework. (Ini akan berada di. NET 5.0, yang memadukan .NET Framework dan .NET Core bersama-sama).
Abel
9

sayangnya saya tidak berpikir ada cara langsung, namun saya pikir Anda dapat menulis metode ekstensi untuk kelas array untuk melakukan ini

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;
        }
    }
}
bashmohandes
sumber
Saya menyukai gagasan ekstensi, semakin saya menggali ini. Terkadang solusi dimuka dan sederhana benar-benar yang terbaik!
patjbs
8

Nah setelah sedikit lebih banyak googling dan membaca saya menemukan ini:

bool[] bPrimes = new bool[1000000];
bPrimes = Array.ConvertAll<bool, bool>(bPrimes, b=> b=true);

Yang pasti lebih dekat dengan apa yang saya cari. Tapi saya tidak yakin apakah itu lebih baik daripada iterasi melalui array asli dalam for-loop dan hanya mengubah nilainya. Setelah tes cepat pada kenyataannya, tampaknya lebih lambat sekitar faktor 5. Jadi bukan solusi yang baik kalau begitu!

patjb
sumber
4
itu mirip dengan apa yang Anda coba lakukan, kecuali itu membuat panggilan fungsi untuk setiap elemen dalam array Anda. Mungkin terlihat jauh lebih baik secara sintaksis, tetapi melakukan lebih banyak pekerjaan ...
Nader Shirazie
ya, itu tampak seperti hanya untuk loop melakukan pekerjaan dan hal-hal lain
patjbs
Itu menciptakan array baru (tidak mengubah instance asli).
Jeppe Stig Nielsen
7

Bagaimana dengan implementasi paralel

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

Ketika hanya menginisialisasi array, kekuatan kode ini tidak dapat dilihat tetapi saya pikir Anda harus melupakan "pure" untuk.

Petar Petrov
sumber
Ini berisiko masalah berbagi palsu, di mana utas berbeda bersaing untuk jalur cache CPU dan karenanya mengurangi kinerja dibandingkan dengan implementasi utas tunggal. Apakah itu terjadi tergantung pada ukuran blok memori per-utas dan arsitektur CPU.
Eric J.
7

Kode di bawah ini menggabungkan iterasi sederhana untuk salinan kecil dan Array.Copy untuk salinan besar

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

Tolok ukur untuk panjang array yang berbeda menggunakan array int [] adalah:

         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

Kolom pertama adalah ukuran array, diikuti oleh waktu penyalinan menggunakan iterasi sederhana (implementasi @JaredPared). Waktu metode ini adalah setelah itu. Ini adalah tolok ukur menggunakan array struct empat bilangan bulat

         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
Panos Theof
sumber
7

Atau ... Anda bisa menggunakan logika terbalik. Biarkan falseberarti truedan sebaliknya.

Contoh kode

// 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!
}
l33t
sumber
solusi lucu, meskipun ini akan jauh lebih sulit dengan ints misalnya karena Anda kehilangan 0.
MrFox
1
ini sebenarnya merupakan opsi yang layak jika Anda "membalikkan logika" pada nama variabel: alih-alih bool[] isVisiblemembuatnyabool[] isHidden
Markus Hütter
1
Orang sepertinya bereaksi seperti ini adalah semacam hack lucu. Ini adalah teknik optimasi yang umum. Jika Anda beruntung, kompiler akan melakukan ini untuk Anda.
l33t
4

ini juga berfungsi ... tetapi mungkin tidak perlu

 bool[] abValues = new bool[1000];
 abValues = abValues.Select( n => n = true ).ToArray<bool>();
Stan R.
sumber
4

Banyak jawaban yang disajikan di sini bermuara pada satu loop yang menginisialisasi elemen array satu per satu, yang tidak memanfaatkan instruksi CPU yang dirancang untuk beroperasi pada blok memori sekaligus.

.Net Standar 2.1 (dalam pratinjau pada saat penulisan ini) menyediakan Array.Fill () , yang cocok untuk implementasi berkinerja tinggi di pustaka runtime (meskipun seperti yang sekarang, .NET Core tampaknya tidak memanfaatkan kemungkinan itu) .

Untuk mereka yang berada di platform sebelumnya, metode ekstensi berikut mengungguli loop sepele dengan margin substansial ketika ukuran array signifikan. Saya membuatnya ketika solusi saya untuk tantangan kode online sekitar 20% dari anggaran waktu yang dialokasikan. Ini mengurangi runtime sekitar 70%. Dalam hal ini, pengisian array dilakukan di dalam loop lain. BLOCK_SIZE ditetapkan oleh firasat daripada eksperimen. Beberapa optimisasi dimungkinkan (misalnya menyalin semua byte yang telah ditetapkan ke nilai yang diinginkan daripada blok ukuran tetap).

internal const int BLOCK_SIZE = 256;
public static void Fill<T>(this T[] array, T value)
{
    if (array.Length < 2 * BLOCK_SIZE)
    {
        for (int i = 0; i < array.Length; i++) array[i] = value;
    }
    else
    {
        int fullBlocks = array.Length / BLOCK_SIZE;
        // Initialize first block
        for (int j = 0; j < BLOCK_SIZE; j++) array[j] = value;
        // Copy successive full blocks
        for (int blk = 1; blk < fullBlocks; blk++)
        {
            Array.Copy(array, 0, array, blk * BLOCK_SIZE, BLOCK_SIZE);
        }

        for (int rem = fullBlocks * BLOCK_SIZE; rem < array.Length; rem++)
        {
            array[rem] = value;
        }
    }
}
Eric J.
sumber
3

Jika Anda berencana untuk hanya menetapkan beberapa nilai dalam array, tetapi sebagian besar ingin mendapatkan nilai default (khusus), Anda dapat mencoba sesuatu seperti ini:

public class SparseArray<T>
{
    private Dictionary<int, T> values = new Dictionary<int, T>();

    private T defaultValue;

    public SparseArray(T defaultValue)
    {
        this.defaultValue = defaultValue;
    }

    public T this [int index]
    {
      set { values[index] = value; }
      get { return values.ContainsKey(index) ? values[index] ? defaultValue; }
    }
}

Anda mungkin perlu mengimplementasikan antarmuka lain untuk membuatnya berguna, seperti yang ada di array itu sendiri.

Douglas
sumber
3

Tidak ada cara untuk mengatur semua elemen dalam array sebagai operasi tunggal, KECUALI, nilai itu adalah nilai default jenis elemen.

Misalnya, jika ini adalah array bilangan bulat, Anda dapat mengatur semuanya ke nol dengan satu operasi, seperti: Array.Clear(...)

James
sumber
2

Saya sadar saya terlambat ke pesta, tapi ini ide. Tulis pembungkus yang memiliki operator konversi ke dan dari nilai terbungkus sehingga dapat digunakan sebagai pengganti untuk jenis yang dibungkus. Ini sebenarnya terinspirasi oleh jawaban yang terdengar konyol dari @ l33t.

Pertama (berasal dari C ++) saya menyadari bahwa di C # default ctor tidak dipanggil ketika elemen array dibangun. Alih-alih - bahkan di hadapan konstruktor default yang ditentukan pengguna! - semua elemen array diinisialisasi nol. Itu mengejutkan saya.

Jadi kelas wrapper yang hanya menyediakan ctor default dengan nilai yang diinginkan akan bekerja untuk array dalam C ++ tetapi tidak dalam C #. Solusinya adalah membiarkan pembungkus tipe memetakan 0 ke nilai benih yang diinginkan pada saat konversi. Dengan begitu nol nilai yang diinisialisasi tampaknya diinisialisasi dengan seed untuk semua tujuan praktis:

public struct MyBool
{
    private bool _invertedValue;

    public MyBool(bool b) 
    {   
        _invertedValue = !b;
    }

    public static implicit operator MyBool(bool b)
    {
        return new MyBool(b);
    }

    public static implicit operator bool(MyBool mb)
    {
        return !mb._invertedValue;
    }

}

static void Main(string[] args)
{
        MyBool mb = false; // should expose false.
        Console.Out.WriteLine("false init gives false: " 
                              + !mb);

        MyBool[] fakeBoolArray = new MyBool[100];

        Console.Out.WriteLine("Default array elems are true: " 
                              + fakeBoolArray.All(b => b) );

        fakeBoolArray[21] = false;
        Console.Out.WriteLine("Assigning false worked: " 
                              + !fakeBoolArray[21]);

        fakeBoolArray[21] = true;
        // Should define ToString() on a MyBool,
        // hence the !! to force bool
        Console.Out.WriteLine("Assigning true again worked: " 
                              + !!fakeBoolArray[21]);
}

Pola ini berlaku untuk semua tipe nilai. Seseorang dapat misalnya memetakan 0 hingga 4 untuk int jika diinginkan inisialisasi dengan 4 dll.

Saya ingin membuat templat seperti yang dimungkinkan dalam C ++, memberikan nilai seed sebagai parameter templat, tapi saya mengerti itu tidak mungkin dalam C #. Atau apakah saya melewatkan sesuatu? (Tentu saja dalam pemetaan C ++ tidak diperlukan sama sekali karena seseorang dapat memberikan ctor default yang akan dipanggil untuk elemen array.)

FWIW, ini setara dengan C ++: https://ideone.com/wG8yEh .

Peter - Pasang kembali Monica
sumber
2

Jika Anda dapat membalikkan logika Anda, Anda dapat menggunakan Array.Clear()metode untuk mengatur array boolean ke false.

        int upperLimit = 21;
        double optimizeMe = Math.Sqrt(upperLimit);

        bool[] seiveContainer = new bool[upperLimit];
        Array.Clear(seiveContainer, 0, upperLimit);
superstewie
sumber
2

Jika Anda menggunakan .NET Core, .NET Standard> = 2.1, atau bergantung pada paket System.Memory, Anda juga dapat menggunakan Span<T>.Fill()metode ini:

var valueToFill = 165;
var data = new int[100];

data.AsSpan().Fill(valueToFill);

// print array content
for (int i = 0; i < data.Length; i++)
{
    Console.WriteLine(data[i]);
}

https://dotnetfiddle.net/UsJ9bu

Apollo3zehn
sumber
2

Berikut versi lain untuk kami pengguna Kerangka yang ditinggalkan oleh Microsoft. Ini 4 kali lebih cepat Array.Cleardan lebih cepat daripada solusi Panos Theof dan paralel Eric J dan Petar Petrov - hingga dua kali lebih cepat untuk array besar.

Pertama, saya ingin menyajikan kepada Anda leluhur fungsi tersebut, karena itu membuatnya lebih mudah untuk memahami kodenya. Kinerja-bijaksana ini cukup setara dengan kode Panos Theof, dan untuk beberapa hal yang mungkin sudah cukup:

public static void Fill<T> (T[] array, int count, T value, int threshold = 32)
{
    if (threshold <= 0)
        throw new ArgumentException("threshold");

    int current_size = 0, keep_looping_up_to = Math.Min(count, threshold);

    while (current_size < keep_looping_up_to)
        array[current_size++] = value;

    for (int at_least_half = (count + 1) >> 1; current_size < at_least_half; current_size <<= 1)
        Array.Copy(array, 0, array, current_size, current_size);

    Array.Copy(array, 0, array, current_size, count - current_size);
}

Seperti yang Anda lihat, ini didasarkan pada penggandaan berulang dari bagian yang sudah diinisialisasi. Ini sederhana dan efisien, tetapi bertabrakan dengan arsitektur memori modern. Oleh karena itu lahir versi yang menggunakan penggandaan hanya untuk membuat blok seed yang ramah cache, yang kemudian diledakkan berulang-ulang di atas area target:

const int ARRAY_COPY_THRESHOLD = 32;  // 16 ... 64 work equally well for all tested constellations
const int L1_CACHE_SIZE = 1 << 15;

public static void Fill<T> (T[] array, int count, T value, int element_size)
{
    int current_size = 0, keep_looping_up_to = Math.Min(count, ARRAY_COPY_THRESHOLD);

    while (current_size < keep_looping_up_to)
        array[current_size++] = value;

    int block_size = L1_CACHE_SIZE / element_size / 2;
    int keep_doubling_up_to = Math.Min(block_size, count >> 1);

    for ( ; current_size < keep_doubling_up_to; current_size <<= 1)
        Array.Copy(array, 0, array, current_size, current_size);

    for (int enough = count - block_size; current_size < enough; current_size += block_size)
        Array.Copy(array, 0, array, current_size, block_size);

    Array.Copy(array, 0, array, current_size, count - current_size);
}

Catatan: kode sebelumnya diperlukan (count + 1) >> 1sebagai batas untuk loop pengganda untuk memastikan bahwa operasi penyalinan akhir memiliki cukup makanan untuk mencakup semua yang tersisa. Ini tidak akan menjadi kasus perhitungan ganjil jika count >> 1digunakan sebagai gantinya. Untuk versi saat ini, ini tidak penting karena loop salinan linier akan mengambil setiap kelonggaran.

Ukuran sel array harus dilewatkan sebagai parameter karena - boggles pikiran - generik tidak diizinkan untuk digunakan sizeofkecuali mereka menggunakan constraint ( unmanaged) yang mungkin atau mungkin tidak tersedia di masa depan. Perkiraan yang salah bukanlah masalah besar tetapi kinerja terbaik jika nilainya akurat, karena alasan berikut:

  • Meremehkan ukuran elemen dapat menyebabkan ukuran blok lebih besar dari setengah cache L1, sehingga meningkatkan kemungkinan data sumber salinan diusir dari L1 dan harus diambil kembali dari tingkat cache yang lebih lambat.

  • Menaksir terlalu tinggi ukuran elemen menghasilkan utilisasi yang kurang dari cache L1 CPU, yang berarti loop copy blok linier dieksekusi lebih sering daripada pemanfaatan optimal. Dengan demikian, lebih dari overhead loop / panggilan tetap yang dikeluarkan daripada yang diperlukan.

Berikut adalah patokan mengadu kode saya Array.Cleardan tiga solusi lainnya yang disebutkan sebelumnya. Pengaturan waktu adalah untuk mengisi bilangan bulat array ( Int32[]) dari ukuran yang diberikan. Untuk mengurangi variasi yang disebabkan oleh cache vagaries dll. Setiap tes dieksekusi dua kali, kembali ke belakang, dan waktunya diambil untuk eksekusi kedua.

array size   Array.Clear      Eric J.   Panos Theof  Petar Petrov   Darth Gizka
-------------------------------------------------------------------------------
     1000:       0,7 µs        0,2 µs        0,2 µs        6,8 µs       0,2 µs 
    10000:       8,0 µs        1,4 µs        1,2 µs        7,8 µs       0,9 µs 
   100000:      72,4 µs       12,4 µs        8,2 µs       33,6 µs       7,5 µs 
  1000000:     652,9 µs      135,8 µs      101,6 µs      197,7 µs      71,6 µs 
 10000000:    7182,6 µs     4174,9 µs     5193,3 µs     3691,5 µs    1658,1 µs 
100000000:   67142,3 µs    44853,3 µs    51372,5 µs    35195,5 µs   16585,1 µs 

Jika kinerja kode ini tidak mencukupi maka jalan yang menjanjikan akan memparalelkan loop copy linier (dengan semua utas menggunakan blok sumber yang sama), atau teman lama kita P / Invoke.

Catatan: membersihkan dan mengisi blok biasanya dilakukan dengan rutinitas runtime yang bercabang ke kode yang sangat khusus menggunakan instruksi MMX / SSE dan yang lainnya, jadi dalam lingkungan yang layak orang hanya akan memanggil setara moral masing-masing std::memsetdan dijamin tingkat kinerja profesional. TKI, berdasarkan haknya fungsi perpustakaan Array.Clearharus meninggalkan semua versi lintingan tangan kami dalam debu. Fakta bahwa itu sebaliknya menunjukkan betapa jauh dari hal-hal yang sebenarnya. Hal yang sama berlaku karena harus menggulung sendiri Fill<>di tempat pertama, karena masih hanya dalam Core dan Standard tetapi tidak dalam Framework. .NET telah ada selama hampir dua puluh tahun sekarang dan kita masih harus P / Panggil kiri dan kanan untuk hal-hal yang paling mendasar atau menggulung ...

DarthGizka
sumber
0

Berikut ini adalah penilaian lain System.Collections.BitArrayyang memiliki konstruktor tersebut.

bool[] result = new BitArray(1000000, true).Cast<bool>().ToArray();

atau

bool[] result = new bool[1000000];
new BitArray(1000000, true).CopyTo(result, 0);
fubo
sumber
0

Buat kelas privat di dalam di mana Anda membuat array dan memiliki pengambil dan penyetel untuk itu. Kecuali jika Anda memerlukan setiap posisi dalam array untuk menjadi sesuatu yang unik, seperti acak, lalu gunakan int? sebagai array dan kemudian dapatkan jika posisinya nol, isi posisi itu dan kembalikan nilai acak yang baru.

IsVisibleHandler
{

  private bool[] b = new bool[10000];

  public bool GetIsVisible(int x)
  {
  return !b[x]
  }

  public void SetIsVisibleTrueAt(int x)
  {
  b[x] = false //!true
  }
}

Atau gunakan

public void SetIsVisibleAt(int x, bool isTrue)
{
b[x] = !isTrue;
}

Sebagai setter.

Peter J
sumber
-2
Boolean[] data = new Boolean[25];

new Action<Boolean[]>((p) => { BitArray seed = new BitArray(p.Length, true); seed.CopyTo(p, 0); }).Invoke(data);
ldsmithperrin
sumber
Harap gunakan format yang lebih baik dan mungkin beberapa kata yang menjelaskan sehingga orang lain dapat memahami solusi Anda dengan lebih baik.
Gorgsenegger
1
Anda dapat menggunakan ini untuk meningkatkan kinerja inisialisasi dengan mempartisi array target dan menyalin seed ke berbagai partisi. Ini hanya dimaksudkan untuk memberikan ide - Ini adalah yang pertama dan merupakan posting terakhir saya.
ldsmithperrin