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

Я знаю, что экземпляры массивов типов значений в 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; } 

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

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

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

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

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

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

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

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

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

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

Если ваш массив настолько велик, вы должны использовать 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); 

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

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

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

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

 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(this T[] array, T defaultVaue) { if (array == null) return; for (int i = 0; i < array.Length; i++) { array[i] = defaultVaue; } } } 

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

 public static void InitializeArray(T[] array, T value) { var cores = Environment.ProcessorCount; ArraySegment[] segments = new ArraySegment[cores]; var step = array.Length / cores; for (int i = 0; i < cores; i++) { segments[i] = new ArraySegment(array, i * step, step); } var remaining = array.Length % cores; if (remaining != 0) { var lastIndex = segments.Length - 1; segments[lastIndex] = new ArraySegment(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); } 

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

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

  public static void Populate( 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 

Или … вы могли бы просто использовать инвертированную логику. Пусть 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! } 

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

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

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

 public class SparseArray { private Dictionary values = new Dictionary(); 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; } } } 

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

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

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

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

  int upperLimit = 21; double optimizeMe = Math.Sqrt(upperLimit); bool[] seiveContainer = new bool[upperLimit]; Array.Clear(seiveContainer, 0, upperLimit); 

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

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

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

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

Есть еще несколько ответов на этот (дублирующий?) Вопрос: что эквивалентно memset в C #?

Кто-то сравнивает альтернативы (они включали небезопасную версию, но они не пытались memset ): http://techmikael.blogspot.co.uk/2009/12/filling-array-with-default-value.html

Вот еще одна оценка с System.Collections.BitArray которая имеет такой конструктор.

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

или

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

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

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

Как сеттер.

Я тестировал его для себя, и кажется, что метод Enumerable.Repeat в десять раз быстрее.

  [Test] public void Create_array_with_Array_Copy() { var size = 3000 * 30000; var arr = new int [size]; var val = 0xFF; FillArray (arr, val); } [Test] public void Create_array_with_loop () { var size = 3000 * 30000; var arr = new int [size]; var val = 0xFF; Populate (arr, val); } [Test] public void Create_array_with_Repeat () { var size = 3000 * 30000; var arr = new int [size]; var val = 0xFF; Enumerable.Repeat (val, size); } static void FillArray (T [] arr, T fillValue) { int i = 0; if (arr.Length > 16) { { do { arr [i++] = fillValue; } while (i < arr.Length); while (i + 16 < arr.Length) { Array.Copy (arr, 0, arr, i, 16); i = i + 16; } } while (i < arr.Length) { arr [i++] = fillValue; } } } static void Populate (T [] arr, T value) { for (int i = 0; i < arr.Length; i++) { arr [i] = value; } } 

рассматривает Ронни

 Boolean[] data = new Boolean[25]; new Action((p) => { BitArray seed = new BitArray(p.Length, true); seed.CopyTo(p, 0); }).Invoke(data); 
  • Программный эквивалент по умолчанию (Тип)
  • Как загрузить пакеты в R автоматически?
  • Значение по умолчанию для типа в Runtime
  • Инициализация нормального массива с одним значением по умолчанию
  • как изменить браузер по умолчанию с помощью c # или командного файла
  • Изменить статус по умолчанию Magento для дублированных продуктов
  • Почему в параметрах C ++ последнее значение должно быть добавлено последними?
  • Что означает «default» после объявления функции classа?
  • Интерфейс с методами по умолчанию vs Абстрактный class в Java 8
  • Почему компилятор Scala запрещает перегруженные методы с аргументами по умолчанию?
  • Почему компилятор не может вывести тип шаблона из аргументов по умолчанию?
  • Давайте будем гением компьютера.