Как заполнить / создать экземпляр массива C # с одним значением?

206

Я знаю, что созданные экземпляры массивов типов значений в C # автоматически заполняются значением типа по умолчанию (например, false для bool, 0 для int и т. Д.).

Есть ли способ автоматического заполнения массива начальным значением, которое не является значением по умолчанию? Или о создании или о встроенном методе впоследствии (как в Java Arrays.fill () )? Скажем, я хотел логический массив, который по умолчанию был true, а не false. Есть ли встроенный способ сделать это, или вам просто нужно перебрать массив с циклом 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;
 }

Необходимость перебирать массив и «сбрасывать» каждое значение в true кажется неэффективной. Есть ли что-нибудь вокруг этого? Может быть, перевернув все значения?

После того, как мы напишем этот вопрос и подумаем над ним, я предполагаю, что значения по умолчанию являются просто результатом того, как C # обрабатывает выделение памяти этими объектами за кулисами, поэтому я думаю, что, вероятно, это невозможно сделать. Но я все еще хотел бы знать наверняка!

patjbs
источник
Я обычно меняю имя с is_found на is_still_hiding. Люблю ответы, хотя, мне нужно было сделать подобное для массива int в тестовом примере. (хороший вопрос)
Ctrl-Alt-Delor

Ответы:

146

Не знаю метода фреймворка, но вы можете написать быстрый помощник, который сделает это за вас.

public static void Populate<T>(this T[] arr, T value ) {
  for ( int i = 0; i < arr.Length;i++ ) {
    arr[i] = value;
  }
}
JaredPar
источник
3
Предпочитаю ++ i вместо i ++, если вам не нужна копия.
void.pointer
24
i ++ копирует i, увеличивает i и возвращает исходное значение. ++ Я просто возвращаю увеличенное значение. Поэтому ++ я быстрее, что может быть значительным в больших циклах, о которых мы говорим здесь.
Tenpn
57
@RobertDailey: Это оптимизация компилятора, и больше не соответствует действительности. Я только что проверил свою веру: если возвращаемое значение i ++ ни для чего не используется, то компилятор автоматически скомпилирует его как ++ i. Кроме того, даже когда я использую возвращаемое значение, разница в производительности настолько мала, что мне нужно было привести крайний случай для его измерения. Даже тогда это приводило к разному времени выполнения всего на несколько процентов.
Эдвард Нед Харви
8
Я написал такой метод расширения, но он заставил его вернуть исходный массив, чтобы учесть цепочку методов, такую ​​как:int[] arr = new int[16].Populate(-1);
Gutblender
2
Перейдите voidна T[]и затем вы можете сделатьvar a = new int[100].Polupate(1)
Орад
198
Enumerable.Repeat(true, 1000000).ToArray();
Rony
источник
70
Хотя это работает, это не очень хорошее решение, потому что оно очень медленное; на самом деле это примерно в 4 раза медленнее, чем итерация с циклом for.
patjbs
4
да, это правда, когда мы рассматриваем производительность, цикл for быстрее
Rony
6
Чтобы увидеть реальный тест, посмотрите на C # Initialize Array .
Theknut
4
Enumerable.ToArrayне знает размер перечисляемой последовательности, поэтому он должен угадать размер массива. Это означает, что вы будете получать распределения массива каждый раз, когда ToArrayбуфер будет превышен, плюс еще одно выделение в конце для усечения. Там также накладные расходы, связанные с перечислимым объектом.
Эдвард Брей
5
Просто обратите внимание, что со ссылочными типами это заполнит весь массив всеми ссылками на один и тот же объект. Если это не то, что вам нужно, и вы действительно хотите создавать разные объекты для каждого элемента массива, см. Stackoverflow.com/a/44937053/23715 .
Алекс Че
74

Создайте новый массив с тысячей trueзначений:

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

Точно так же вы можете генерировать целочисленные последовательности:

var items = Enumerable.Range(0, 1000).ToArray();  // 0..999
bytebender
источник
8
Неплохо, но он все еще медленнее цикла for примерно в 4 раза
patjbs
1
теоретически patjbs в будущем Enumerable.Repeat будет работать быстрее, поскольку будет использовать параллельную реализацию.
Петар Петров
1
@PetarPetrov Это никогда не произойдет из-за перегрузки кэша. Я вполне уверен, что из-за природы кэша ЦП выполнение параллельной работы над одним массивом всегда будет медленнее, несмотря ни на что, потому что компьютер ожидает синхронную работу и загружает данные соответствующим образом.
TernaryTopiary
намеренная пессимизация! = отсутствие преждевременной оптимизации.
Денис Гладкий
24

Для больших массивов или массивов переменного размера вы, вероятно, должны использовать:

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

Для небольшого массива вы можете использовать синтаксис инициализации коллекции в C # 3:

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

Преимущество синтаксиса инициализации коллекции состоит в том, что вам не нужно использовать одно и то же значение в каждом слоте, и вы можете использовать выражения или функции для инициализации слота. Кроме того, я думаю, что вы избегаете затрат на инициализацию слота массива значением по умолчанию. Так, например:

bool[] vals = new bool[]{ false, true, false, !(a ||b) && c, SomeBoolMethod() };
LBushkin
источник
И чтобы инициализировать массив float []:float[] AlzCalDefault = new float[] {(float) 0.5, 18, 500, 1, 0};
Джим Лахман
Инициализация FWIW массива может быть выполнена в любой версии C #, например:bool[] vals = { false, true, false, !(a || b) && c, SomeBoolMethod() };
Питер ван дер Хейден,
24

Если ваш массив такой большой, вы должны использовать BitArray. Он использует 1 бит для каждого bool вместо байта (как в массиве bools), также вы можете установить все биты в true с помощью битовых операторов. Или просто инициализировать на true. Если вам нужно сделать это только один раз, это будет стоить дороже.

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
источник
17

Вы можете использовать Array.Fillв .NET Core 2.0+ и .NET Standard 2.1+.

ЮФО
источник
Превосходно! Хотя имейте в виду, что это относительно новый метод. Он доступен в .NET Core 2.0+ и .NET Standard 2.1, но, в частности, не доступен ни в одной из версий .NET Framework. (это будет в .NET 5.0, которая объединяет .NET Framework и .NET Core вместе).
Авель
9

к сожалению, я не думаю, что есть прямой путь, однако я думаю, что вы можете написать метод расширения для класса массива, чтобы сделать это

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
источник
Мне нравится идея расширения, чем больше я копаюсь в этом. Иногда простое и простое решение действительно лучшее!
patjbs
8

Ну, после еще немного поиска в Google и чтения я нашел это:

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

Что, безусловно, ближе к тому, что я ищу. Но я не уверен, что это лучше, чем перебирать исходный массив в цикле for и просто изменять значения. После быстрого теста он кажется медленнее примерно в 5 раз. Так что тогда это не очень хорошее решение!

patjbs
источник
4
это похоже на то, что вы пытаетесь сделать, за исключением вызова функции для каждого элемента в вашем массиве. Синтаксически это может выглядеть намного лучше, но это делает гораздо больше работы ...
Надер Ширази
да, похоже, что цикл for просто выполняет работу почти так же, как и все остальное
patjbs
Создает новый массив (не меняет исходный экземпляр).
Джеппе Стиг Нильсен
7

Как насчет параллельной реализации

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

Когда только инициализируется массив, мощь этого кода не видна, но я думаю, что вы обязательно должны забыть о «чистом» для.

Петр Петров
источник
Это создает риск ложного совместного использования, при котором разные потоки конкурируют за строки кэша ЦП и, следовательно, снижают производительность по сравнению с однопоточной реализацией. То, произойдет ли это, зависит от размера блоков памяти для каждого потока и архитектуры процессора.
Эрик Дж
7

Приведенный ниже код объединяет простую итерацию для маленьких копий и Array.Copy для больших копий.

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

Тесты для различной длины массива с использованием массива int []:

         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

Первые столбцы - это размер массива, за которым следует время копирования с использованием простой итерации (реализация @JaredPared). Время этого метода после этого. Это тесты, использующие массив из структуры из четырех целых чисел

         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

Или ... вы можете просто использовать инвертированную логику. Пусть falseзначит trueи наоборот.

Пример кода

// 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
источник
забавное решение, хотя это будет намного сложнее, например, с помощью целых чисел, потому что вы потеряете 0.
MrFox
1
на самом деле это жизнеспособный вариант, если вы «инвертируете логику» в имени переменной: вместо того, bool[] isVisibleчтобы делать этоbool[] isHidden
Маркус Хюттер
1
Люди, кажется, реагируют так, будто это какой-то смешной взлом. Это распространенная техника оптимизации. Если вам повезет, компилятор сделает это за вас.
l33t
4

это тоже работает ... но может быть ненужным

 bool[] abValues = new bool[1000];
 abValues = abValues.Select( n => n = true ).ToArray<bool>();
Стэн Р.
источник
4

Многие из представленных здесь ответов сводятся к циклу, который инициализирует массив по одному элементу за раз, в котором не используются инструкции процессора, предназначенные для одновременной работы с блоком памяти.

.Net Standard 2.1 (в предварительном просмотре на момент написания этой статьи) предоставляет Array.Fill () , который обеспечивает высокопроизводительную реализацию в библиотеке времени выполнения (хотя на данный момент .NET Core , похоже, не использует эту возможность) ,

Для тех на более ранних платформах следующий метод расширения значительно превосходит тривиальный цикл, когда размер массива значительный. Я создал его, когда мое решение для онлайн-кода кода было около 20% от выделенного времени. Это сократило время выполнения примерно на 70%. В этом случае заполнение массива было выполнено внутри другого цикла. BLOCK_SIZE был задан чувством кишки, а не экспериментом. Возможна некоторая оптимизация (например, копирование всех байтов, которые уже установлены на желаемое значение, а не на блок фиксированного размера).

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

Если вы планируете установить только несколько значений в массиве, но хотите большую часть времени получать (пользовательское) значение по умолчанию, вы можете попробовать что-то вроде этого:

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

Вам, вероятно, потребуется реализовать другие интерфейсы, чтобы сделать его полезным, например, для самого массива .

Дуглас
источник
3

Невозможно установить все элементы в массиве как одну операцию, UNLESS, это значение является значением по умолчанию для типов элементов.

Например, если это массив целых чисел, вы можете установить их все в ноль с помощью одной операции, например, так: Array.Clear(...)

Джеймс
источник
2

Я понимаю, что опоздал на вечеринку, но вот идея. Напишите оболочку, у которой есть операторы преобразования в и из упакованного значения, чтобы его можно было использовать в качестве замены для упакованного типа. На самом деле это было вдохновлено глупо звучащим ответом @ l33t.

Во-первых (из C ++) я понял, что в C # ctor по умолчанию не вызывается при создании элементов массива. Вместо этого - даже при наличии определяемого пользователем конструктора по умолчанию! - все элементы массива инициализируются нулями. Это меня удивило.

Таким образом, класс-обертка, который просто предоставляет ctor по умолчанию с желаемым значением, будет работать для массивов в C ++, но не в C #. Обходной путь - позволить типу оболочки отобразить 0 на желаемое начальное значение после преобразования. Таким образом, нулевые инициализированные значения кажутся инициализированными с начальным числом для всех практических целей:

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

Этот шаблон применим ко всем типам значений. Можно, например, отобразить от 0 до 4 для целых, если желательна инициализация с 4 и т. Д.

Я хотел бы сделать его шаблон, как это было бы возможно в C ++, предоставив начальное значение в качестве параметра шаблона, но я понимаю, что это невозможно в C #. Или я что-то упустил? (Конечно, в C ++ отображение вообще не нужно, потому что можно предоставить ctor по умолчанию, который будет вызываться для элементов массива.)

FWIW, вот эквивалент C ++: https://ideone.com/wG8yEh .

Питер - Восстановить Монику
источник
2

Если вы можете инвертировать свою логику, вы можете использовать Array.Clear()метод для установки логического массива в false.

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

        bool[] seiveContainer = new bool[upperLimit];
        Array.Clear(seiveContainer, 0, upperLimit);
superstewie
источник
2

Если вы используете .NET Core, .NET Standard> = 2.1 или зависите от пакета System.Memory, вы также можете использовать Span<T>.Fill()метод:

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
источник
2

Вот еще одна версия для нас, пользователей Framework, от которой отказались Microsoft. Это в 4 раза быстрее Array.Clearи быстрее, чем решение Panos Theof и параллельное решение Eric J и Petar Petrov. - в два раза быстрее для больших массивов.

Сначала я хочу представить вам предка функции, потому что это облегчает понимание кода. С точки зрения производительности это в значительной степени наравне с кодом Panos Theof, а для некоторых вещей этого может уже хватить:

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

Как видите, это основано на повторном удвоении уже инициализированной части. Это просто и эффективно, но оно противоречит современной архитектуре памяти. Отсюда родилась версия, которая использует удвоение только для создания удобного для кэша начального блока, который затем итеративно обрабатывается по целевой области:

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

Примечание: предыдущий код был необходим в (count + 1) >> 1качестве ограничения для цикла удвоения, чтобы гарантировать, что в последней операции копирования будет достаточно фуража, чтобы покрыть все, что осталось. Это было бы не так для нечетных подсчетов, если count >> 1бы вместо этого использовались. Для текущей версии это не имеет значения, поскольку линейный цикл копирования устраняет любую слабину.

Размер ячейки массива должен быть передан в качестве параметра, потому что - уму непостижимо - непатентованные средства не могут использоваться, sizeofесли они не используют ограничение ( unmanaged), которое может или не может стать доступным в будущем. Неправильные оценки не имеют большого значения, но производительность является наилучшей, если значение является точным по следующим причинам:

  • Недооценка размера элемента может привести к размерам блоков, превышающим половину кэша L1, что увеличивает вероятность того, что исходные данные копии будут удалены из L1, и их придется повторно выбирать из более медленных уровней кэша.

  • Завышение размера элемента приводит к недостаточному использованию кэша L1 ЦП, что означает, что цикл копирования линейного блока выполняется чаще, чем при оптимальном использовании. Таким образом, возникает больше фиксированных накладных расходов цикла / вызова, чем это строго необходимо.

Вот тест, с которым сравнивается мой код, Array.Clearи три других решения, упомянутых ранее. Время для заполнения целочисленных массивов ( Int32[]) заданных размеров. Чтобы уменьшить отклонения, вызванные капризами кеша и т. Д., Каждый тест был выполнен дважды, и время было взято для второго выполнения.

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 

Если производительность этого кода будет недостаточной, то многообещающим способом будет параллельное выполнение цикла линейного копирования (со всеми потоками, использующими один и тот же исходный блок) или нашего старого доброго друга P / Invoke.

Примечание: очистка и заполнение блоков обычно выполняются подпрограммами времени выполнения, которые переходят к узкоспециализированному коду с использованием инструкций MMX / SSE и тому подобного, поэтому в любой достойной среде можно просто вызвать соответствующий моральный эквивалент std::memsetи быть уверенным в профессиональных уровнях производительности. Таким образом, по праву библиотечная функция Array.Clearдолжна оставлять все наши свернутые вручную версии в пыли. Тот факт, что все наоборот, показывает, насколько далеки от этого дела. То же самое относится и к тому, что нужно катиться самостоятельно Fill<>, потому что это все еще только в Core и Standard, но не в Framework. .NET существует уже почти двадцать лет, и нам все еще приходится P / Invoke влево и вправо для самых элементарных вещей или прокручивать свои собственные ...

DarthGizka
источник
0

Вот еще один пример, с System.Collections.BitArrayкоторым есть такой конструктор.

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

или

bool[] result = new bool[1000000];
new BitArray(1000000, true).CopyTo(result, 0);
Fubo
источник
0

Создайте закрытый класс внутри, где вы создаете массив, и для него есть метод получения и установки. Если вам не нужно, чтобы каждая позиция в массиве была чем-то уникальным, например, случайным, тогда используйте int? как массив, а затем при получении, если позиция равна нулю, заполните эту позицию и верните новое случайное значение.

IsVisibleHandler
{

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

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

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

Или использовать

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

Как сеттер.

Питер Дж
источник
-2
Boolean[] data = new Boolean[25];

new Action<Boolean[]>((p) => { BitArray seed = new BitArray(p.Length, true); seed.CopyTo(p, 0); }).Invoke(data);
ldsmithperrin
источник
Пожалуйста, используйте лучшее форматирование и, возможно, несколько поясняющих слов, чтобы другие могли лучше понять ваше решение.
Горгзенеггер
1
Вы можете использовать это для повышения производительности инициализации путем разбиения целевого массива и копирования начальных значений в различные разделы. Это было только для того, чтобы дать представление - это мой первый и последний пост.
ldsmithperrin