¿Cómo llenar / instanciar una matriz C # con un solo valor?

205

Sé que las matrices instanciadas de tipos de valor en C # se rellenan automáticamente con el valor predeterminado del tipo (por ejemplo, falso para bool, 0 para int, etc.).

¿Hay alguna manera de rellenar automáticamente una matriz con un valor inicial que no sea el predeterminado? ¿Ya sea en la creación o en un método incorporado después (como Arrays.fill () de Java )? Digamos que quería una matriz booleana que fuera verdadera por defecto, en lugar de falsa. ¿Hay una forma integrada de hacer esto, o solo tienes que recorrer la matriz con un bucle 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;
 }

Tener que iterar a través de la matriz y "restablecer" cada valor a verdadero parece ineficaz. ¿Hay alguna forma de evitar esto? ¿Quizás cambiando todos los valores?

Después de escribir esta pregunta y pensar en ello, supongo que los valores predeterminados son simplemente el resultado de cómo C # maneja la asignación de memoria de estos objetos detrás de escena, así que imagino que probablemente no sea posible hacer esto. ¡Pero todavía me gustaría saberlo con certeza!

patjbs
fuente
Por lo general, cambio el nombre de is_found a is_still_hiding. Sin embargo, me encantan las respuestas, necesitaba hacer una matriz similar de int en un caso de prueba. (buena pregunta)
ctrl-alt-delor

Respuestas:

146

No conozco un método de marco, pero podría escribir un ayudante rápido para que lo haga por usted.

public static void Populate<T>(this T[] arr, T value ) {
  for ( int i = 0; i < arr.Length;i++ ) {
    arr[i] = value;
  }
}
JaredPar
fuente
3
Prefiere ++ i en lugar de i ++ si no necesitas la copia.
void.pointer
24
i ++ copia i, incrementa i y devuelve el valor original. ++ i solo devuelve el valor incrementado. Por lo tanto, ++ i es más rápido, lo que puede ser significativo en bucles grandes como los que estamos hablando aquí.
Tenpn
57
@RobertDailey: Esa es una optimización del compilador, y ya no es verdad. Acabo de probar para verificar mi creencia: si el valor de retorno de i ++ no se usa para nada, entonces el compilador lo compilará como ++ i automáticamente para usted. Además, incluso cuando uso el valor de retorno, la diferencia de rendimiento es tan pequeña que tuve que hacer un caso extremo para poder medirlo. Incluso entonces, solo resultó en un tiempo de ejecución diferente.
Edward Ned Harvey
8
Escribí un método de extensión como este, pero tuve que devolver la matriz original para permitir el encadenamiento de métodos como:int[] arr = new int[16].Populate(-1);
Gutblender
2
Cambie voida T[]y luego puede hacerlovar a = new int[100].Polupate(1)
orad
198
Enumerable.Repeat(true, 1000000).ToArray();
Rony
fuente
70
Si bien esto funciona, no es realmente una buena solución porque es muy lento; De hecho, es aproximadamente 4 veces más lento que iterar con un bucle for.
patjbs
44
Si eso es cierto, si tenemos en cuenta el rendimiento del bucle for es más rápido
Rony
66
Para ver algunos puntos de referencia reales, eche un vistazo a C # Initialize Array .
theknut
44
Enumerable.ToArrayno conoce el tamaño de la secuencia enumerable, por lo que tiene que adivinar el tamaño de la matriz. Eso significa que obtendrá asignaciones de matriz cada vez ToArrayque se exceda el búfer, más una asignación más al final para el recorte. También hay gastos generales relacionados con el objeto enumerable.
Edward Brey
55
Solo una nota, que con los tipos de referencia esto llenará toda la matriz con todas las referencias al mismo objeto único. Si esto no es lo que desea y realmente desea generar diferentes objetos para cada elemento de la matriz, consulte stackoverflow.com/a/44937053/23715 .
Alex Che
74

Cree una nueva matriz con mil truevalores:

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

Del mismo modo, puede generar secuencias enteras:

var items = Enumerable.Range(0, 1000).ToArray();  // 0..999
bytebender
fuente
8
No está mal, pero aún así es más lento que un bucle en un factor de 4x
patjbs
1
patjbs en teoría en el futuro Enumerable.Repeat funcionará más rápido porque usará una implementación paralela.
Petar Petrov
1
@PetarPetrov Esto nunca sucederá debido al intercambio de caché. Estoy bastante seguro de que, debido a la naturaleza de la memoria caché de la CPU, el trabajo en paralelo en una sola matriz siempre será más lento, ya que la computadora espera un trabajo sincrónico y carga los datos adecuadamente.
TernaryTopiary
pesimismo previsto! = falta de optimización prematura.
Denis Gladkiy
24

Para matrices grandes o matrices que serán de tamaño variable, probablemente debería usar:

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

Para una matriz pequeña, puede usar la sintaxis de inicialización de colección en C # 3:

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

El beneficio de la sintaxis de inicialización de la colección es que no tiene que usar el mismo valor en cada ranura y puede usar expresiones o funciones para inicializar una ranura. Además, creo que evita el costo de inicializar la ranura de la matriz al valor predeterminado. Así por ejemplo:

bool[] vals = new bool[]{ false, true, false, !(a ||b) && c, SomeBoolMethod() };
LBushkin
fuente
Y para inicializar una matriz float []:float[] AlzCalDefault = new float[] {(float) 0.5, 18, 500, 1, 0};
Jim Lahman,
La inicialización de FWIW de una matriz se puede hacer en cualquier versión de C # como:bool[] vals = { false, true, false, !(a || b) && c, SomeBoolMethod() };
Peter van der Heijden
24

Si su matriz es tan grande, debe usar BitArray. Utiliza 1 bit para cada bool en lugar de un byte (como en una matriz de bools), también puede establecer todos los bits en true con operadores de bits. O simplemente inicializar en verdadero. Si solo necesitas hacerlo una vez, solo costará más.

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);
Señor Fox
fuente
17

Puede usar Array.Fillen .NET Core 2.0+ y .NET Standard 2.1+.

juFo
fuente
¡Excelente! Aunque tenga en cuenta que es un método relativamente nuevo. Está disponible en .NET Core 2.0+ y .NET Standard 2.1, pero específicamente no en ninguna de las versiones de .NET Framework. (estará en .NET 5.0, que combina .NET Framework y .NET Core juntos).
Abel
9

desafortunadamente no creo que haya una forma directa, sin embargo, creo que puedes escribir un método de extensión para que la clase de matriz haga esto

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
fuente
Me gusta la idea de extensión cuanto más profundizo en esto. ¡A veces, la solución simple y directa es realmente la mejor!
patjbs
8

Bueno, después de buscar un poco más en Google y leer, encontré esto:

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

Que sin duda está más cerca de lo que estoy buscando. Pero no estoy seguro si eso es mejor que iterar a través de la matriz original en un ciclo for y simplemente cambiar los valores. Después de una prueba rápida, de hecho, parece más lento en un factor de 5. ¡Entonces no es realmente una buena solución!

patjbs
fuente
44
eso es similar a lo que está tratando de hacer, excepto que está haciendo una llamada de función para cada elemento en su matriz. Puede parecer mucho más agradable sintácticamente, pero su hacer mucho más trabajo ...
Nader Shirazie
Sí, parece que un bucle simplemente hace el trabajo casi tan bien como cualquier otra cosa
Patjbs
Crea una nueva matriz (no cambia la instancia original).
Jeppe Stig Nielsen
7

¿Qué pasa con una implementación paralela?

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

Cuando solo se inicializa una matriz, no se puede ver el poder de este código, pero creo que definitivamente debes olvidarte de lo "puro".

Petar Petrov
fuente
Esto conlleva el problema del uso compartido falso, en el que diferentes subprocesos compiten por las líneas de caché de la CPU y, por lo tanto, reducen el rendimiento en comparación con una implementación de un solo subproceso. Si eso sucede depende del tamaño de los bloques de memoria por subproceso y la arquitectura de la CPU.
Eric J.
7

El siguiente código combina una iteración simple para copias pequeñas y Array. Copie para copias grandes

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

Los puntos de referencia para diferentes longitudes de matriz usando una matriz int [] son:

         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

Las primeras columnas son el tamaño de la matriz, seguido del tiempo de copia mediante una iteración simple (implementación @JaredPared). El tiempo de este método es después de eso. Estos son los puntos de referencia que utilizan una matriz de una estructura de cuatro enteros

         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
fuente
7

O ... simplemente podrías usar lógica invertida. Dejar falsesignificar truey viceversa.

Muestra de código

// 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
fuente
solución divertida, aunque esto sería mucho más difícil, por ejemplo, con ints porque pierdes el 0.
MrFox
1
esta es realmente una opción viable si "invierte la lógica" en el nombre de la variable: en lugar de bool[] isVisiblehacerlobool[] isHidden
Markus Hütter
1
La gente parece reaccionar como si fuera una especie de truco gracioso. Es una técnica de optimización común. Si tienes suerte, el compilador lo hará por ti.
l33t
4

esto también funciona ... pero podría ser innecesario

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

Muchas de las respuestas presentadas aquí se reducen a un ciclo que inicializa la matriz un elemento a la vez, que no aprovecha las instrucciones de la CPU diseñadas para operar en un bloque de memoria a la vez.

.Net Standard 2.1 (en versión preliminar a partir de este escrito) proporciona Array.Fill () , que se presta a una implementación de alto rendimiento en la biblioteca de tiempo de ejecución (aunque, a partir de ahora, .NET Core no parece aprovechar esa posibilidad) .

Para aquellos en plataformas anteriores, el siguiente método de extensión supera a un bucle trivial por un margen sustancial cuando el tamaño de la matriz es significativo. Lo creé cuando mi solución para un desafío de código en línea era alrededor del 20% sobre el presupuesto de tiempo asignado. Redujo el tiempo de ejecución en aproximadamente un 70%. En este caso, el relleno de la matriz se realizó dentro de otro bucle. BLOCK_SIZE se estableció por instinto en lugar de experimentar. Algunas optimizaciones son posibles (por ejemplo, copiar todos los bytes ya establecidos en el valor deseado en lugar de un bloque de tamaño fijo).

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.
fuente
3

Si planea establecer solo algunos de los valores en la matriz, pero desea obtener el valor predeterminado (personalizado) la mayor parte del tiempo, puede intentar algo como esto:

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

Probablemente necesitará implementar otras interfaces para que sea útil, como las de la matriz .

Douglas
fuente
3

No hay forma de establecer todos los elementos en una matriz como una sola operación, A MENOS, ese valor es el valor predeterminado de los tipos de elementos.

Por ejemplo, si se trata de una matriz de enteros, puede establecerlos en cero con una sola operación, de esta manera: Array.Clear(...)

James
fuente
2

Me doy cuenta de que llego tarde a la fiesta, pero aquí hay una idea. Escriba un contenedor que tenga operadores de conversión hacia y desde el valor empaquetado para que pueda usarse como un sustituto para el tipo empaquetado. En realidad, esto se inspiró en la respuesta tonta de @ l33t.

Primero (viniendo de C ++) me di cuenta de que en C # no se llama a un ctor predeterminado cuando se construyen los elementos de una matriz. En cambio, ¡incluso en presencia de un constructor predeterminado definido por el usuario! - Todos los elementos de la matriz están inicializados en cero. Eso me sorprendió.

Por lo tanto, una clase de contenedor que simplemente proporciona un ctor predeterminado con el valor deseado funcionaría para matrices en C ++ pero no en C #. Una solución alternativa es dejar que el tipo de contenedor se asigne 0 al valor inicial deseado después de la conversión. De esa manera, los valores inicializados cero parecen inicializarse con la semilla para todos los fines prácticos:

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

Este patrón es aplicable a todos los tipos de valores. Uno podría, por ejemplo, asignar de 0 a 4 para las entradas si se desea la inicialización con 4, etc.

Me encantaría crear una plantilla como sería posible en C ++, proporcionando el valor de inicialización como parámetro de plantilla, pero entiendo que eso no es posible en C #. ¿O me estoy perdiendo algo? (Por supuesto, en mapeo C ++ no es necesario en absoluto porque uno puede proporcionar un ctor predeterminado que se llamará para elementos de matriz).

FWIW, aquí hay un equivalente de C ++: https://ideone.com/wG8yEh .

Peter - Restablece a Monica
fuente
2

Si puede invertir su lógica, puede usar el Array.Clear()método para establecer la matriz booleana en falso.

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

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

Si está en .NET Core, .NET Standard> = 2.1, o depende del paquete System.Memory, también puede usar el Span<T>.Fill()método:

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

Apolo3zehn
fuente
2

Aquí hay otra versión para nosotros, usuarios de Framework abandonados por Microsoft. Es 4 veces más rápido que Array.Cleary más rápido que la solución de Panos Theof y Eric J y una paralela de Petar Petrov - hasta dos veces más rápido para grandes matrices.

Primero quiero presentarles el antepasado de la función, porque eso facilita la comprensión del código. En cuanto al rendimiento, esto está bastante a la par con el código de Panos Theof, y para algunas cosas que ya pueden ser suficientes:

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

Como puede ver, esto se basa en la duplicación repetida de la parte ya inicializada. Esto es simple y eficiente, pero está en conflicto con las arquitecturas de memoria modernas. Por lo tanto, nació una versión que usa la duplicación solo para crear un bloque de semillas amigable con la caché, que luego se lanza de forma iterativa sobre el área objetivo:

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: el código anterior era necesario (count + 1) >> 1como límite para el ciclo de duplicación para garantizar que la operación de copia final tenga suficiente forraje para cubrir todo lo que queda. Este no sería el caso para los recuentos impares si count >> 1se usaran en su lugar. Para la versión actual esto no tiene importancia ya que el bucle de copia lineal recogerá cualquier holgura.

El tamaño de una celda de matriz debe pasarse como un parámetro porque, la mente alucina, no se permite el uso de genéricos a sizeofmenos que usen una restricción ( unmanaged) que puede estar disponible o no en el futuro. Las estimaciones incorrectas no son un gran problema, pero el rendimiento es mejor si el valor es exacto, por las siguientes razones:

  • Subestimar el tamaño del elemento puede dar lugar a tamaños de bloque superiores a la mitad de la memoria caché L1, lo que aumenta la probabilidad de que los datos de origen de la copia sean expulsados ​​de L1 y tengan que volverse a buscar desde niveles de memoria caché más lentos.

  • Sobreestimar el tamaño del elemento da como resultado una infrautilización de la memoria caché L1 de la CPU, lo que significa que el bucle de copia en bloque lineal se ejecuta con más frecuencia de lo que sería con una utilización óptima. Por lo tanto, se incurre en una mayor sobrecarga de bucle / llamada fija de lo estrictamente necesario.

Aquí hay un punto de referencia que enfrenta mi código Array.Cleary las otras tres soluciones mencionadas anteriormente. Los tiempos son para llenar matrices enteras ( Int32[]) de los tamaños dados. Para reducir la variación causada por los caprichos de la memoria caché, etc., cada prueba se ejecutó dos veces, una tras otra, y los tiempos se tomaron para la segunda ejecución.

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 

Si el rendimiento de este código no es suficiente, una vía prometedora sería paralelizar el bucle de copia lineal (con todos los hilos utilizando el mismo bloque de origen), o nuestro buen viejo amigo P / Invoke.

Nota: la limpieza y el llenado de bloques normalmente se realiza mediante rutinas de tiempo de ejecución que se ramifican a código altamente especializado utilizando instrucciones MMX / SSE y demás, por lo que en cualquier entorno decente uno simplemente llamaría el equivalente moral respectivo std::memsety estaría seguro de los niveles de rendimiento profesional. IOW, por derecho, la función de biblioteca Array.Cleardebería dejar todas nuestras versiones enrolladas a mano en el polvo. El hecho de que sea al revés muestra cuán fuera de control están realmente las cosas. Lo mismo ocurre con tener que rodar la propia Fill<>en primer lugar, porque todavía está solo en Core y Standard, pero no en el Framework. .NET ha existido durante casi veinte años y todavía tenemos que P / Invocar de izquierda a derecha para las cosas más básicas o rodar el nuestro ...

DarthGizka
fuente
0

Aquí hay otro appraoch con el System.Collections.BitArrayque tiene tal constructor.

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

o

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

Haga una clase privada en el interior donde cree la matriz y tenga un getter y setter para ello. A menos que necesite que cada posición en la matriz sea algo único, como aleatorio, use int? como una matriz y luego obtener si la posición es igual a nula, llenar esa posición y devolver el nuevo valor aleatorio.

IsVisibleHandler
{

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

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

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

O usar

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

Como acomodador.

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

new Action<Boolean[]>((p) => { BitArray seed = new BitArray(p.Length, true); seed.CopyTo(p, 0); }).Invoke(data);
ldsmithperrin
fuente
Utilice un mejor formato y quizás algunas palabras explicativas para que otros puedan entender mejor su solución.
Gorgsenegger
1
Puede usar esto para aumentar el rendimiento de la inicialización al particionar la matriz de destino y copiar la semilla en las distintas particiones. Esto solo tenía la intención de dar una idea: esta es mi primera publicación y la última.
ldsmithperrin