Come popolare / creare un'istanza di un array C # con un singolo valore?


205

So che le matrici istanziate di tipi di valore in C # vengono popolate automaticamente con il valore predefinito del tipo (ad esempio false per bool, 0 per int, ecc.).

C'è un modo per popolare automaticamente un array con un valore seed non predefinito? O sulla creazione o su un metodo incorporato in seguito (come Java's Arrays.fill () )? Supponiamo che volessi un array booleano che fosse vero per impostazione predefinita, anziché falso. C'è un modo integrato per farlo, o devi semplicemente scorrere l'array con un ciclo 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;
 }

Dover iterare attraverso l'array e "resettare" ogni valore su true sembra inefficace. C'è un modo per aggirare questo? Forse capovolgendo tutti i valori?

Dopo aver scritto questa domanda e averci pensato, immagino che i valori predefiniti siano semplicemente il risultato di come C # gestisce l'allocazione di memoria di questi oggetti dietro le quinte, quindi immagino che probabilmente non sia possibile farlo. Ma vorrei ancora saperlo con certezza!


Di solito cambio il nome da is_found a is_still_hiding. Adoro le risposte, però, ho dovuto fare simili per array di int in un caso di test. (bella domanda)
ctrl-alt-delor

Risposte:


146

Non conosci un metodo framework ma potresti scrivere un aiuto veloce per farlo per te.

public static void Populate<T>(this T[] arr, T value ) {
  for ( int i = 0; i < arr.Length;i++ ) {
    arr[i] = value;
  }
}

3
Preferisci ++ i invece di i ++ se non ti serve la copia.
void.pointer

24
i ++ copia i, incrementa i e restituisce il valore originale. ++ I restituisce solo il valore incrementato. Pertanto ++ i è più veloce, il che può essere significativo in loop di grandi dimensioni come stiamo parlando qui.
tenpn

57
@RobertDailey: questa è un'ottimizzazione del compilatore e non è più vera. Ho appena testato per verificare la mia convinzione: se il valore restituito di i ++ non viene utilizzato per nulla, il compilatore lo compilerà automaticamente come ++ i per te. Inoltre, anche quando uso il valore restituito, la differenza di prestazioni è così piccola che ho dovuto fare un caso estremo per misurarlo. Anche allora, ha comportato solo un po 'di tempo di esecuzione diverso.
Edward Ned Harvey,

8
Ho scritto un metodo di estensione come questo ma l'ho fatto restituire l'array originale per consentire il concatenamento del metodo come:int[] arr = new int[16].Populate(-1);
Gutblender

2
Cambiare voidper T[]e allora si può farevar a = new int[100].Polupate(1)
ORAD

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

70
Mentre funziona non è davvero una buona soluzione perché è molto lento; è circa 4 volte più lento dell'iterazione con un ciclo for in effetti.
Patjbs,

4
sì, è vero, se consideriamo le prestazioni il ciclo for è più veloce
Rony,

6
Per vedere alcuni benchmark reali dai un'occhiata a C # Initialize Array .
Theknut,

4
Enumerable.ToArraynon conosce le dimensioni della sequenza enumerabile, quindi deve indovinare le dimensioni dell'array. Ciò significa che otterrai allocazioni di array ogni volta ToArrayche viene superato il buffer, più un'ulteriore allocazione alla fine per il trim. C'è anche un sovraccarico coinvolto nell'oggetto enumerabile.
Edward Brey,

5
Solo una nota, che con i tipi di riferimento riempirà l'intero array con tutti i riferimenti allo stesso singolo oggetto. Se questo non è ciò che si desidera e si desidera effettivamente generare oggetti diversi per ciascun elemento dell'array, consultare stackoverflow.com/a/44937053/23715 .
Alex Che l'

74

Crea un nuovo array con mille truevalori:

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

Allo stesso modo, puoi generare sequenze di numeri interi:

var items = Enumerable.Range(0, 1000).ToArray();  // 0..999

8
Non male, ma è ancora più lento di un ciclo for di circa un fattore 4x
patjbs

1
patjbs in teoria Enumerable in futuro. Repeat si esibirà più velocemente perché utilizzerà un'implementazione parallela.
Petar Petrov,

1
@PetarPetrov Questo non accadrà mai a causa del blocco della cache. Sono abbastanza certo che a causa della natura della cache della CPU, l'esecuzione del lavoro in parallelo su un singolo array sarà sempre più lenta, indipendentemente dal fatto che il computer si aspetti un lavoro sincrono e carichi i dati in modo appropriato.
TernaryTopiary

pessimizzazione prevista! = mancanza di ottimizzazione prematura.
Denis Gladkiy,

24

Per array di grandi dimensioni o array di dimensioni variabili, è consigliabile utilizzare:

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

Per array di piccole dimensioni è possibile utilizzare la sintassi di inizializzazione della raccolta in C # 3:

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

Il vantaggio della sintassi di inizializzazione della raccolta è che non è necessario utilizzare lo stesso valore in ogni slot e è possibile utilizzare espressioni o funzioni per inizializzare uno slot. Inoltre, penso che tu eviti il ​​costo di inizializzazione dello slot dell'array al valore predefinito. Quindi, per esempio:

bool[] vals = new bool[]{ false, true, false, !(a ||b) && c, SomeBoolMethod() };

E per inizializzare un array float []:float[] AlzCalDefault = new float[] {(float) 0.5, 18, 500, 1, 0};
Jim Lahman,

L'inizializzazione FWIW di un array può essere eseguita in qualsiasi versione di C # come:bool[] vals = { false, true, false, !(a || b) && c, SomeBoolMethod() };
Peter van der Heijden,

24

Se il tuo array è così grande, dovresti usare BitArray. Usa 1 bit per ogni bool anziché un byte (come in una matrice di bool) inoltre puoi impostare tutti i bit su true con gli operatori bit. O semplicemente inizializzare su true. Se devi farlo una sola volta, ti costerà solo di più.

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

17

È possibile utilizzare Array.Fillin .NET Core 2.0+ e .NET Standard 2.1+.


Eccellente! Tuttavia, tieni presente che si tratta di un metodo relativamente nuovo. È disponibile in .NET Core 2.0+ e .NET Standard 2.1, ma in particolare non in nessuna delle versioni di .NET Framework. (sarà in .NET 5.0, che unisce .NET Framework e .NET Core insieme).
Abel,

9

sfortunatamente non penso che ci sia un modo diretto, tuttavia penso che tu possa scrivere un metodo di estensione per la classe array per farlo

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

Mi piace l'idea di estensione più approfondisco questo. A volte la soluzione semplice e anticipata è davvero la migliore!
patjbs,

8

Bene dopo un po 'più di ricerche su Google e ho trovato questo:

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

Il che è sicuramente più vicino a quello che sto cercando. Ma non sono sicuro che sia meglio che iterare l'array originale in un ciclo for e cambiare semplicemente i valori. Dopo un rapido test, infatti, appare più lento di circa un fattore 5. Quindi non è davvero una buona soluzione!


4
è simile a quello che stai cercando di fare, tranne per il fatto che effettua una chiamata di funzione per ciascun elemento dell'array. Può sembrare molto più sintattico, ma sta facendo molto più lavoro ...
Nader Shirazie,

sì, sembra un semplice ciclo per fare il lavoro così come qualsiasi altra cosa
patjbs

Crea un nuovo array (non cambia l'istanza originale).
Jeppe Stig Nielsen,

7

Che dire di un'implementazione parallela

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

Quando si inizializza solo un array, la potenza di questo codice non può essere vista, ma penso che dovresti assolutamente dimenticare il "puro" per.


Ciò comporta il problema della falsa condivisione, in cui thread diversi competono per le linee della cache della CPU e quindi riducono le prestazioni rispetto a un'implementazione a thread singolo. Se ciò accade dipende dalla dimensione dei blocchi di memoria per thread e dall'architettura della CPU.
Eric J.

7

Il codice seguente combina una semplice iterazione per copie di piccole dimensioni e Array.Copy per copie di grandi dimensioni

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

I benchmark per diverse lunghezze di array usando un array int [] sono:

         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

Le prime colonne sono le dimensioni dell'array, seguite dal momento della copia usando una semplice iterazione (implementazione @JaredPared). Il tempo di questo metodo è dopo. Questi sono i parametri di riferimento che utilizzano una matrice di una struttura di quattro numeri interi

         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

7

Oppure ... potresti semplicemente usare la logica invertita. Let falsemean truee viceversa.

Esempio di codice

// 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!
}

soluzione divertente, anche se questo sarebbe molto più difficile con ad esempio ints perché perdi lo 0.
MrFox

1
questa è in realtà un'opzione praticabile se "inverti la logica" sul nome della variabile: invece di bool[] isVisiblerenderlabool[] isHidden
Markus Hütter

1
Le persone sembrano reagire in questo modo è una specie di hack divertente. È una tecnica di ottimizzazione comune. Se sei fortunato, il compilatore lo farà per te.
l33t,

4

anche questo funziona ... ma potrebbe non essere necessario

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

4

Molte delle risposte qui presentate si riducono a un ciclo che inizializza l'array un elemento alla volta, che non sfrutta le istruzioni della CPU progettate per funzionare contemporaneamente su un blocco di memoria.

.Net Standard 2.1 (in anteprima al momento della stesura di questo documento) fornisce Array.Fill () , che si presta ad un'implementazione ad alte prestazioni nella libreria di runtime (anche se al momento .NET Core non sembra sfruttare questa possibilità) .

Per quelli su piattaforme precedenti, il seguente metodo di estensione supera un ciclo banale di un margine sostanziale quando la dimensione dell'array è significativa. L'ho creato quando la mia soluzione per una sfida del codice online era di circa il 20% rispetto al budget assegnato. Ha ridotto l'autonomia di circa il 70%. In questo caso, il riempimento dell'array è stato eseguito all'interno di un altro loop. BLOCK_SIZE è stato impostato dall'intestino piuttosto che dall'esperimento. Sono possibili alcune ottimizzazioni (ad esempio, la copia di tutti i byte già impostati sul valore desiderato anziché su un blocco di dimensioni fisse).

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

3

Se stai pianificando di impostare solo alcuni dei valori nell'array, ma desideri ottenere il valore predefinito (personalizzato) per la maggior parte del tempo, puoi provare qualcosa del genere:

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

Probabilmente dovrai implementare altre interfacce per renderlo utile, come quelle sull'array stesso.


3

Non è possibile impostare tutti gli elementi in un array come un'unica operazione, A MENO CHE tale valore sia il valore predefinito dei tipi di elemento.

Ad esempio, se si tratta di un array di numeri interi, è possibile impostarli tutti a zero con un'unica operazione, in questo modo: Array.Clear(...)


2

Mi rendo conto di essere in ritardo alla festa, ma ecco un'idea. Scrivi un wrapper che ha operatori di conversione da e verso il valore di wrapping in modo che possa essere utilizzato come supporto per il tipo di wrapping. Questo in realtà è stato ispirato dalla risposta sciocca di @ l33t.

Innanzitutto (proveniente da C ++) mi sono reso conto che in C # un ctor predefinito non viene chiamato quando vengono costruiti gli elementi di un array. Invece - anche in presenza di un costruttore predefinito definito dall'utente! - tutti gli elementi dell'array sono inizializzati con zero. Questo mi ha sorpreso.

Quindi una classe wrapper che fornisce semplicemente un ctor predefinito con il valore desiderato funzionerebbe per le matrici in C ++ ma non in C #. Una soluzione alternativa consiste nel consentire al tipo di wrapper di mappare 0 sul valore seed desiderato al momento della conversione. In questo modo, zero valori inizializzati sembrano essere inizializzati con il seme per tutti gli scopi pratici:

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

Questo modello è applicabile a tutti i tipi di valore. Si potrebbe ad esempio mappare da 0 a 4 per gli ints se si desidera inizializzare con 4 ecc.

Mi piacerebbe crearne un modello come sarebbe possibile in C ++, fornendo il valore seed come parametro template, ma capisco che non è possibile in C #. Oppure mi sfugge qualcosa? (Naturalmente nella mappatura C ++ non è affatto necessario perché si può fornire un ctor predefinito che verrà chiamato per gli elementi dell'array.)

FWIW, ecco un equivalente C ++: https://ideone.com/wG8yEh .


2

Se è possibile invertire la logica, è possibile utilizzare il Array.Clear()metodo per impostare la matrice booleana su false.

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

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

2

Se sei su .NET Core, .NET Standard> = 2.1 o dipendi dal pacchetto System.Memory, puoi anche usare il Span<T>.Fill()metodo:

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


2

Ecco un'altra versione per noi utenti Framework abbandonati da Microsoft. Si tratta di 4 volte più veloce Array.Cleare più veloce di soluzione di Panos Theof e Eric J di e una parallela di Petar Petrov - fino a due volte più veloce per grandi array.

Per prima cosa voglio presentarti l'antenato della funzione, perché ciò rende più semplice la comprensione del codice. Per quanto riguarda le prestazioni, questo è praticamente alla pari con il codice di Panos Theof, e per alcune cose che potrebbero già essere sufficienti:

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

Come puoi vedere, questo si basa sul ripetuto raddoppio della parte già inizializzata. Questo è semplice ed efficiente, ma corre contro le moderne architetture di memoria. Da qui è nata una versione che utilizza il raddoppio solo per creare un blocco seed compatibile con la cache, che viene quindi fatto saltare in modo iterativo sull'area di destinazione:

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

Nota: il codice precedente era necessario (count + 1) >> 1come limite per il ciclo di raddoppio per garantire che l'operazione di copia finale abbia abbastanza foraggio per coprire tutto ciò che resta. Questo non sarebbe il caso di conteggi dispari se count >> 1si dovesse usare invece. Per la versione attuale questo non ha alcun significato poiché il ciclo di copia lineare rileverà qualsiasi gioco.

La dimensione di una cella di matrice deve essere passata come parametro perché - la mente vacilla - i generici non possono usare a sizeofmeno che non utilizzino un vincolo ( unmanaged) che potrebbe o non potrebbe essere disponibile in futuro. Le stime errate non sono un grosso problema, ma le prestazioni sono migliori se il valore è accurato, per i seguenti motivi:

  • Sottovalutare la dimensione dell'elemento può portare a blocchi di dimensioni superiori alla metà della cache L1, aumentando così la probabilità che i dati di origine della copia vengano sfrattati da L1 e che debbano essere recuperati da livelli di cache più lenti.

  • La sopravvalutazione della dimensione dell'elemento comporta un sottoutilizzo della cache L1 della CPU, il che significa che il ciclo di copia del blocco lineare viene eseguito più spesso di quanto sarebbe con un utilizzo ottimale. Pertanto, si verifica più dell'overhead fisso di loop / chiamata di quanto strettamente necessario.

Ecco un benchmark che mette a confronto il mio codice Array.Cleare le altre tre soluzioni menzionate in precedenza. I tempi sono per il riempimento di array di numeri interi ( Int32[]) delle dimensioni indicate. Al fine di ridurre le variazioni causate dai capricci della cache, ecc. Ogni test è stato eseguito due volte, schiena contro schiena, e i tempi sono stati presi per la seconda esecuzione.

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 

Se le prestazioni di questo codice non fossero sufficienti, una strada promettente sarebbe quella di parallelizzare il ciclo lineare di copia (con tutti i thread che usano lo stesso blocco sorgente), o il nostro buon vecchio amico P / Invoke.

Nota: la cancellazione e il riempimento di blocchi viene normalmente eseguito da routine di runtime che si diramano verso un codice altamente specializzato utilizzando le istruzioni MMX / SSE e quant'altro, quindi in qualsiasi ambiente decente si potrebbe semplicemente chiamare il rispettivo equivalente morale std::memseted essere certi dei livelli di prestazioni professionali. IOW, per diritto la funzione di libreria Array.Cleardovrebbe lasciare tutte le nostre versioni arrotolate a mano nella polvere. Il fatto che sia il contrario, dimostra quanto siano veramente lontane le cose fuori di testa. Lo stesso vale per doversi spostare da soli Fill<>in primo luogo, perché è ancora solo in Core e Standard ma non nel Framework. .NET è in circolazione da quasi vent'anni ormai e dobbiamo ancora fare P / Invoke a destra e sinistra per le cose più elementari o girare il nostro ...



0

Ecco un'altra valutazione con System.Collections.BitArraycui ha un tale costruttore.

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

o

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

0

Crea una classe privata all'interno del punto in cui crei l'array e disponi di un getter e setter per esso. A meno che non sia necessario che ogni posizione dell'array sia qualcosa di unico, come casuale, quindi utilizzare int? come array e poi get se la posizione è uguale a null riempire quella posizione e restituire il nuovo valore casuale.

IsVisibleHandler
{

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

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

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

Oppure usa

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

Come setter.


-2
Boolean[] data = new Boolean[25];

new Action<Boolean[]>((p) => { BitArray seed = new BitArray(p.Length, true); seed.CopyTo(p, 0); }).Invoke(data);

Utilizza una formattazione migliore e forse alcune parole esplicative in modo che altri possano capire meglio la tua soluzione.
Gorgsenegger,

1
È possibile utilizzarlo per aumentare le prestazioni dell'inizializzazione partizionando l'array di destinazione e copiando il seme nelle varie partizioni. Questo voleva solo dare un'idea - Questo è il mio primo ed è stato il mio ultimo post in assoluto.
ldsmithperrin,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.