Як заповнити / інстанціювати масив C # з одним значенням?


205

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

Чи існує спосіб автоматичного заповнення масиву зі значенням насіння, яке не є типовим? Або після створення, або після вбудованого методу (наприклад, Java Arrays.fill () )? Скажіть, що я хотів логічний масив, який за замовчуванням був істинним, а не 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;
 }

Перехід через масив та "скидання" кожного значення до істинного видається малоефективним. Чи є все-таки навколо цього? Може, перегортаючи всі значення?

Ввівши це запитання і подумавши над ним, я здогадуюсь, що значення за замовчуванням є просто результатом того, як C # обробляє розподіл пам'яті цих об'єктів за кадром, тому я думаю, що цього, мабуть, неможливо. Але я все одно хотів би точно знати!


Зазвичай я змінюю ім'я з 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;
  }
}

3
Віддайте перевагу ++ i замість i ++, якщо копія вам не потрібна.
void.pointer

24
i ++ копіює i, з кроком i, і повертає початкове значення. ++ я просто повертає збільшене значення. Тому ++ i швидше, що може бути суттєвим у великих циклах, як ми говоримо тут.
tenpn

57
@RobertDailey: Це оптимізація компілятора, і це вже не відповідає дійсності. Я щойно перевірив свою перевірку: Якщо повернене значення i ++ ні для чого не використовується, компілятор скомпілює його як ++ i автоматично для вас. Крім того, навіть коли я використовую повернене значення, різниця в продуктивності настільки мала, що мені потрібно було зробити крайній випадок, щоб виміряти його. Вже тоді це призвело лише до декількох відсотків різного часу виконання.
Edward Ned Harvey

8
Я написав такий метод розширення, але мені довелося повернути його початковий масив, щоб дозволити ланцюжок методів, таких як:int[] arr = new int[16].Populate(-1);
Gutblender

2
Перейдіть voidна, T[]і тоді ви можете зробитиvar a = new int[100].Polupate(1)
orad

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

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

8
Непогано, але це все-таки повільніше, ніж для циклу приблизно в 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() };

І ініціалізувати float [] масив:float[] AlzCalDefault = new float[] {(float) 0.5, 18, 500, 1, 0};
Jim Lahman

Ініціалізація масиву FWIW може бути виконана в будь-якій версії C #, наприклад:bool[] vals = { false, true, false, !(a || b) && c, SomeBoolMethod() };
Пітер ван дер Хайден

24

Якщо ваш масив настільки великий, ви повинні використовувати BitArray. Він використовує 1 біт для кожного bool замість байта (як у масиві bools). Ви також можете встановити всі біти для 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);

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

Мені подобається ідея розширення, чим більше я вникаю в це. Іноді наперед і просте рішення справді найкраще!
patjbs

8

Ну а після ще трохи гуглінгу та читання я виявив таке:

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

Що, безумовно, ближче до того, що я шукаю. Але я не впевнений, що це краще, ніж ітерація через оригінальний масив for-loop та просто зміна значень. Після швидкого тестування він виявляється повільніше приблизно в 5 разів. Тож не дуже хороше рішення!


4
це аналогічно тому, що ви намагаєтеся зробити, за винятком того, щоб зробити виклик функції для кожного елемента у масиві. Синтаксично це може виглядати набагато приємніше, але це робить набагато більше роботи ...
Надер Ширазі

так, це схоже на те, що просто для циклу виконує цю роботу так само, як і все інше
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);
}

Коли тільки ініціалізувати масив, потужність цього коду неможливо побачити, але я думаю, ви обов'язково повинні забути про "чистий" для.


Це загрожує проблемою помилкового обміну, в якій різні потоки конкурують за кеш-лінії CPU і, таким чином, знижують продуктивність порівняно з однопотоковою реалізацією. Чи відбудеться це, залежить від розміру блоків пам'яті на одну нитку та архітектури процесора.
Ерік Дж.

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

смішне рішення, хоча все це буде набагато складніше, наприклад, з ints, оскільки ви втрачаєте 0.
MrFox

1
це насправді життєздатний варіант, якщо ви "інвертуєте логіку" на ім'я змінної: замість того, bool[] isVisibleщоб зробити цеbool[] isHidden
Markus Hütter

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

Немає можливості встановити всі елементи в масиві як одну операцію, БЕЗПЕЧНО, це значення є типовим типом елементів.

Наприклад, якщо це масив цілих чисел, ви можете встановити їх на нуль за допомогою однієї операції, наприклад: Array.Clear(...)


2

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

По-перше (з C ++) я зрозумів, що в C # за допомогою типового 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 для ints, якщо потрібна ініціалізація з 4 тощо.

Я хотів би зробити його шаблон, як це було б можливо в C ++, надаючи значення параметра seed як параметр шаблону, але я розумію, що це неможливо в 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);

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


2

Ось ще одна версія для нас, користувачів Framework, відмовилася від Microsoft. Це в 4 рази швидше , як Array.Clearі швидше , ніж рішення Панос Theof в і Ерік Джея і паралельно один Petar Петрова - до двох разів швидше для великих масивів.

Спочатку я хочу представити вам пращура функції, оскільки це полегшує розуміння коду. Виконання продуктивності це майже врівень з кодом 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замість цього використовувати. Для поточної версії це не має ніякого значення, оскільки цикл лінійної копії дозволить отримати будь-яку слабкість.

Розмір комірки масиву повинен бути переданий як параметр, тому що - mind boggles - generics не дозволяється використовувати, 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та бути впевненим у професійних рівнях. IOW, за правами, бібліотечна функція Array.Clearповинна залишати всі наші ручні версії в пилу. Той факт, що це навпаки, свідчить про те, наскільки насправді далекі від удару речі. Це ж стосується того, що потрібно Fill<>спершу розгорнути власне , оскільки воно все ще є лише в Core та Standard, але не в Framework. .NET існує вже майже двадцять років, і нам залишається P / Invoke ліворуч та праворуч на найосновніші речі або прокручувати власні ...



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

0

Створіть приватний клас всередині, де ви складаєте масив, а у нього - getter та setter. Якщо вам не потрібно, щоб кожна позиція в масиві була чимось унікальним, наприклад випадковим, тоді використовуєте 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);

Будь ласка, скористайтеся кращим форматуванням і, можливо, кількома пояснювальними словами, щоб інші могли краще зрозуміти ваше рішення.
Gorgsenegger

1
Ви можете використовувати це для підвищення продуктивності ініціалізації шляхом розподілу цільового масиву та копіювання насіння в різні розділи. Це було покликане лише дати ідею - Це моя перша і була моєю останньою коли-небудь посадою.
ldsmithperrin
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.