Каков наиболее эффективный способ создания массива произвольной длины с нулевым заполнением в JavaScript?
javascript
arrays
разб
источник
источник
let i = 0; Array.from(Array(10), ()=>i++);
Ответы:
ES6 вводит
Array.prototype.fill
. Это можно использовать так:Не уверен, что это быстро, но мне это нравится, потому что это коротко и самоописательно.
Это все еще не в IE ( проверьте совместимость ), но есть доступный polyfill .
источник
new Array(len)
мучительно медленно(arr = []).length = len; arr.fill(0);
о самом быстром решении, которое я когда-либо видел ... или, по крайней мере, связаноarr = Array(n)
и(arr = []).length = n
вести себя одинаково в соответствии со спецификацией. В некоторых реализациях это может быть быстрее, но я не думаю, что есть большая разница.(arr = []).length = 1000;
противarr = new Array(1000);
теста скорости его в обоих Chrome и FF ...new
ужасно медленно. Теперь, если длина массива меньше ... скажем, <50 или около того ... тогдаnew Array()
, кажется, работает лучше. Но ..arr.fill(0)
... все вроде как меняется. Теперь использованиеnew Array()
быстрее в большинстве случаев, за исключением случаев, когда вы достигаете размеров массива> 100000 ... Затем вы снова можете увидеть увеличение скорости. Но если вам на самом деле не нужно предварительно заполнять его нулями и вы можете использовать стандартную группу пустых массивов. Тогда(arr = []).length = x
в моих тестовых случаях большую часть времени я схожу с ума.new Array(5).forEach(val => console.log('hi'));
противnew Array(5).fill(undefined).forEach(val => console.log('hi'));
.Хотя это старая ветка, я хотел добавить к ней свои 2 цента. Не уверен, насколько это медленно / быстро, но это быстрый лайнер. Вот что я делаю:
Если я хочу предварительно заполнить номер:
Если я хочу предварительно заполнить строкой:
Другие ответы предложили:
но если вы хотите 0 (число), а не «0» (ноль внутри строки), вы можете сделать:
источник
Array.apply(null, new Array(5)).map(...)
? Потому что просто делать (новый Array (5)). Map (...) не будет работать, как говорит спецификацияnew
) КогдаArray(5)
вы создаете объект, который выглядит примерно так:{ length: 5, __proto__: Array.prototype }
- попробуйтеconsole.dir( Array(5) )
. Обратите внимание , что он не имеет каких - либо свойств0
,1
,2
и т.д. Но когда вам ,apply
что предArray
конструктору, это , как говорятArray(undefined, undefined, undefined, undefined, undefined)
. И вы получаете объект, который вроде как выглядит{ length: 5, 0: undefined, 1: undefined...}
.map
работ по свойствам0
,1
и т.д., поэтому ваш пример не работает, но когда вы используетеapply
это делает..apply
- это то, что вы хотитеthis
. Для этих целей этоthis
не имеет значения - нас действительно волнует только «особенность» распространения параметров,.apply
поэтому она может иметь любое значение. Мне нравится,null
потому что это дешево, вы, вероятно, не хотите использовать,{}
или,[]
поскольку вы будете создавать экземпляр объекта без причины.Элегантный способ заполнить массив предварительно вычисленными значениями
Вот еще один способ сделать это с помощью ES6, о котором никто еще не упоминал:
Он работает, передавая функцию карты в качестве второго параметра
Array.from
.В приведенном выше примере первый параметр выделяет массив из 3 позиций, заполненных значением,
undefined
а затем лямбда-функция отображает каждую из них на значение0
.Хотя
Array(len).fill(0)
он короче, он не работает, если вам нужно сначала заполнить массив, выполнив какое-то вычисление (я знаю, что вопрос не задавался, но многие в конечном итоге ищут это) .Например, если вам нужен массив с 10 случайными числами:
Это более кратко (и элегантно), чем эквивалент:
Этот метод также можно использовать для генерации последовательностей чисел, используя параметр индекса, предоставленный в обратном вызове:
Бонусный ответ: заполнить массив с помощью String
repeat()
Поскольку этот ответ привлекает большое внимание, я также хотел показать этот крутой трюк. Хотя и не такой полезный, как мой основной ответ, я представлю еще не очень известный, но очень полезный
repeat()
метод String . Вот хитрость:Круто, да?
repeat()
это очень полезный метод для создания строки, которая является повторением исходной строки определенное количество раз. После этого создаемsplit()
для нас массив, который затемmap()
привязывается к нужным значениям. Разбивая его по шагам:источник
repeat
трюк определенно не нужен в производстве,Array.from()
он отлично подходит :-)Короче говоря
Самое быстрое решение
let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;
Кратчайшее (удобное) решение (в 3 раза медленнее для маленьких массивов, немного медленнее для больших (медленнее в Firefox))
Array(n).fill(0)
подробности
Сегодня 2020.06.09 я выполняю тесты на macOS High Sierra 10.13.6 в браузерах Chrome 83.0, Firefox 77.0 и Safari 13.1. Я тестирую выбранные решения для двух тестовых случаев
Выводы
new Array(n)+for
(N), является самым быстрым решением для небольших и больших массивов (кроме Chrome, но там все еще очень быстро) и рекомендуется в качестве быстрого кросс-браузерного решения.new Float32Array(n)
(I) возвращает нестандартный массив (например, вы не можете вызватьpush(..)
его), поэтому я не сравниваю его результаты с другими решениями - однако это решение примерно в 10-20 раз быстрее, чем другие решения для больших массивов во всех браузерахfor
(L, M, N, O) являются быстрыми для небольших массивовfill
(B, C), бывают быстрыми в Chrome и Safari, но удивительно медленнее в Firefox для больших массивов. Они средние быстрые для небольших массивовArray.apply
(P) выбрасывает ошибку для больших массивовПоказать фрагмент кода
Код и пример
Ниже код представляет решения, используемые в измерениях
Показать фрагмент кода
Пример результатов для Chrome
источник
let a=[]; for(i=n;i--;) a.push(0);
- но это в 4 раза медленнее, чемfill(0)
- поэтому я даже не буду обновлять картинку в этом случае.Уже упомянутый метод заполнения ES 6 прекрасно справляется с этой задачей. Большинство современных настольных браузеров уже поддерживают требуемые методы-прототипы Array (Chromium, FF, Edge и Safari) [ 1 ]. Вы можете посмотреть детали на MDN . Простой пример использования
Учитывая текущую поддержку браузера, вы должны быть осторожны, если не уверены, что ваша аудитория использует современные настольные браузеры.
источник
a = Array(10).fill(null).map(() => { return []; });
a = Array(10).fill(0).map( _ => [] );
Примечание добавлено в августе 2013 года, обновлено в феврале 2015 года. Нижеприведенный ответ от 2009 года относится к универсальному
Array
типу JavaScript . Это не относится к новым типизированным массивам, определенным в ES2015 [и доступным сейчас во многих браузерах],Int32Array
и тому подобное. Также обратите внимание, что ES2015 добавляетfill
метод для массивов и типизированных массивов , который, вероятно, будет наиболее эффективным способом их заполнения ...Кроме того, для некоторых реализаций это может иметь большое значение для создания массива. В частности, движок Chrome V8 пытается использовать высокоэффективный массив непрерывной памяти, если сочтет это возможным, переходя на массив на основе объектов только при необходимости.
В большинстве языков это будет предварительно выделено, а затем заполнено нулями, например так:
Но JavaScript-массивы на самом деле не являются массивами , они представляют собой сопоставления ключ / значение, как и все другие объекты JavaScript, так что нет никакого «предварительного выделения» (установка длины не выделяет столько слотов для заполнения), ни есть ли основания полагать, что преимущество обратного отсчета (а именно быстрого выполнения сравнения в цикле) не перевешивается добавлением ключей в обратном порядке, когда реализация, возможно, хорошо оптимизировала их обработку ключей связанные с массивами по теории, вы обычно делаете их по порядку.
Фактически, Мэтью Крамли отметил, что обратный отсчет в Firefox заметно медленнее, чем подсчет, и я могу подтвердить этот результат - это часть массива (цикл до нуля все же быстрее, чем цикл до предела в переменной). Очевидно, что добавление элементов в массив в обратном порядке является медленной операцией в Firefox. На самом деле, результаты могут сильно отличаться от реализации JavaScript (что не так уж удивительно). Вот быстрая и грязная тестовая страница (ниже) для реализации браузера (очень грязная, не дает результатов во время тестов, поэтому обеспечивает минимальную обратную связь и будет работать вне временных рамок скрипта). Я рекомендую освежиться между тестами; FF (по крайней мере) замедляет повторные тесты, если вы этого не сделаете.
Довольно сложная версия, в которой используется Array # concat, работает быстрее, чем прямая инициализация в FF, где-то между 1000 и 2000 массивами элементов. На двигателе Chrome V8, однако, прямой init побеждает каждый раз ...
Вот тестовая страница ( живая копия ):
источник
По умолчанию
Uint8Array
,Uint16Array
иUint32Array
классы держать нули ее ценности, так что вам не нужны никакие сложные методы наполнения, просто сделать:все элементы массива
ary
будут нулями по умолчанию.источник
Array.isArray(ary)
isfalse
. Длина также только для чтения , так что вы не можете нажать новые детали к нему , как сary.push
0
значение по умолчанию.Array.from(new Uint8Array(10))
предоставит обычный массив.Array(n).fill(0)
в Chrome, если вам действительно нужен массив JS. Если вы можете использовать TypedArray, это намного быстрее, чем.fill(0)
, тем не менее, особенно если вы можете использовать значение инициализатора по умолчанию0
. Кажется, не существует конструктора, который принимает значение заполнения и длину, как в C ++std::vector
. Кажется, что для любого ненулевого значения вы должны создать обнуленный TypedArray и затем заполнить его. : /Если вы используете ES6, вы можете использовать Array.from () следующим образом:
Имеет тот же результат, что и
Потому что
источник
Обратите внимание, что
while
обычно более эффективно, чемfor-in
,forEach
и т. Д.источник
i
локальная переменная не является посторонней?length
передается по значению, так что вы должны иметь возможность уменьшить его напрямую.arr[i] = value
). Это намного быстрее, чтобы пройтись от начала до конца и использоватьarr.push(value)
. Это раздражает, потому что я предпочитаю твой метод.используя обозначение объекта
ноль заполнен? подобно...
заполнено "неопределенным" ...
объективная запись с нулями
В качестве примечания, если вы измените прототип Array, оба
а также
будет иметь эти модификации прототипа
В любом случае, я не был бы чрезмерно обеспокоен эффективностью или скоростью этой операции, есть много других вещей, которые вы, вероятно, будете делать, которые гораздо более расточительны и дороги, чем создание массива произвольной длины, содержащей нули.
источник
null
в этом массиве нет s -var x = new Array(7);
new Array(7)
это не создает массив «наполненный неопределенным». Он создает пустой массив длиной 7.(new Array(10)).fill(0)
.Я протестировал все комбинации предварительного выделения / отсутствия предварительного выделения, счета вверх / вниз и циклов for / while в IE 6/7/8, Firefox 3.5, Chrome и Opera.
Приведенные ниже функции всегда были самыми быстрыми или чрезвычайно близкими в Firefox, Chrome и IE8, и не намного медленнее, чем самые быстрые в Opera и IE 6. Это также самое простое и понятное, на мой взгляд. Я нашел несколько браузеров, в которых версия цикла while немного быстрее, поэтому я включил ее и для справки.
или
источник
var array = []
объявление в первую часть цикла for, разделенного только запятой.length
уже заданное значение, чтобы оно не менялось постоянно. На моей машине я получил массив нулей длиной в 1 миллион от 40 мс до 8.for (i = 0, array = []; i < length; ++i) array[i] = val;
.. Меньше блоков? ... во всяком случае, также ... если я установлюarray.length
длину нового массива в длину .. я, похоже, получу еще 10% -15% увеличение скорости FF ... в Chrome, кажется, удваивает скорость ->var i, array = []; array.length = length; while(i < length) array[i++] = val;
(было еще быстрее, если бы я оставил его какfor
цикл ... но инициализация больше не нужна, так чтоwhile
, похоже, в этой версии он работает быстрее)Если вам нужно создать много заполненных нулями массивов разной длины во время выполнения вашего кода, самый быстрый способ, который я нашел для этого, - это создать нулевой массив один раз , используя один из методов, упомянутых в этом разделе, длины который вы знаете, никогда не будет превышен, а затем нарезать этот массив по мере необходимости.
Например (используя функцию из выбранного выше ответа для инициализации массива), создайте заполненный нулями массив длины maxLength как переменную, видимую для кода, который требует нулевых массивов:
Теперь нарезайте этот массив каждый раз, когда вам нужен заполненный нулями массив длины requiredLength < maxLength :
Во время выполнения моего кода я создавал массивы, заполненные нулями, тысячи раз, это значительно ускорило процесс.
источник
источник
new Array(size+1).join("x").split("x").map(function() { return 0; })
чтобы получить реальные цифрыnew Array(size+1).join('0').split('').map(Number)
Я не имею ничего против:
предложенный Zertosh, но в новых расширениях массива ES6 вы можете сделать это изначально с помощью
fill
метода. Теперь IE edge, Chrome и FF его поддерживают, но проверьте таблицу совместимостиnew Array(3).fill(0)
даст тебе[0, 0, 0]
. Вы можете заполнить массив любым значением, таким какnew Array(5).fill('abc')
(даже объекты и другие массивы).Кроме того, вы можете изменить предыдущие массивы с помощью fill:
что дает вам:
[1, 2, 3, 9, 9, 6]
источник
То, как я обычно это делаю (и удивительно быстро), использует
Uint8Array
. Например, создание заполненного нулями вектора из 1M элементов:Я пользователь Linux и всегда работал на меня, но однажды у друга, использующего Mac, было несколько ненулевых элементов. Я думал, что его машина работает со сбоями, но все же вот самый безопасный способ, который мы нашли, это исправить:
Edited
Chrome 25.0.1364.160
Firefox 20.0
Отсутствует самый важный тест (по крайней мере, для меня): Node.js. Я подозреваю, что это близко к тесту Chrome.
источник
Используя lodash или подчеркивание
Или, если у вас есть массив, и вы хотите массив такой же длины
источник
_.range(0, length, 0)
, я считаю. Lodash не имеет конечного значенияРешение ES6:
источник
Начиная с ECMAScript2016 , существует один четкий выбор для больших массивов.
Поскольку этот ответ по-прежнему отображается в верхней части результатов поиска Google, вот ответ на 2017 год.
Вот текущий jsbench с несколькими десятками популярных методов, включая многие, предложенные до сих пор по этому вопросу. Если вы найдете лучший способ, пожалуйста, добавьте, раскошелиться и поделиться.
Я хочу отметить, что не существует истинного наиболее эффективного способа создания массива произвольной длины с нулевым заполнением. Вы можете оптимизировать скорость, ясность и ремонтопригодность - либо можно считать более эффективным выбором в зависимости от потребностей проекта.
При оптимизации по скорости вы хотите: создать массив с использованием буквального синтаксиса; установите длину, инициализируйте переменную итерации и выполните итерацию по массиву, используя цикл while. Вот пример.
Другая возможная реализация будет:
Но я настоятельно не рекомендую использовать эту вторую имплантацию на практике, поскольку она менее понятна и не позволяет вам поддерживать область видимости для переменной массива.
Они значительно быстрее, чем заполнение цикла for, и примерно на 90% быстрее, чем стандартный метод
Но этот метод заполнения по-прежнему является наиболее эффективным выбором для небольших массивов из-за его ясности, краткости и удобства обслуживания. Разница в производительности, скорее всего, не убьет вас, если вы не создадите много массивов с длинами порядка тысяч и более.
Несколько других важных замечаний. Большинство руководств по стилю рекомендуют вам больше не использовать
var
без особой причины при использовании ES6 или новее. Используйтеconst
для переменных, которые не будут переопределены, иlet
для переменных, которые будут. MDN и руководство Стиля AirBnB в больших местах , чтобы пойти для получения более подробной информации о передовой практике. Вопросы не касались синтаксиса, но важно, чтобы люди, плохо знакомые с JS, знали об этих новых стандартах при поиске среди множества старых и новых ответов.источник
Создать новый массив
Чтобы добавить некоторые значения в конце существующего массива
[...existingArray, ...new Array(numberOfElementsToAdd).fill(0)]
пример
источник
Не видел этот метод в ответах, поэтому вот он:
В результате вы получите нулевой массив длиной 200:
Я не уверен в производительности этого кода, но это не должно быть проблемой, если вы используете его для относительно небольших массивов.
источник
источник
Эта
concat
версия намного быстрее в моих тестах на Chrome (2013-03-21). Около 200 мс для 10 000 000 элементов против 675 для прямой инициализации.Бонус: если вы хотите заполнить ваш массив строками, это краткий способ сделать это (не так быстро, как
concat
если бы):источник
Я тестировал отличный ответ TJ Crowder и придумал рекурсивное слияние на основе решения concat, которое превосходит любое в его тестах в Chrome (я не тестировал другие браузеры).
вызовите метод с
makeRec(29)
.источник
Как насчет
new Array(51).join('0').split('')
?источник
.map(function(a){return +a})
?Возможно, стоит отметить, что
Array.prototype.fill
это было добавлено как часть предложения ECMAScript 6 (Гармония) . Я предпочел бы использовать полифилл, написанный ниже, прежде чем рассматривать другие варианты, упомянутые в теме.источник
Самый короткий для кода цикла
Безопасная версия вар
источник
n
это будет короче:for(var a=[];n--;a[n]=0);
источник
Моя самая быстрая функция была бы:
Использование встроенных функций push и shift для добавления элементов в массив выполняется намного быстрее (примерно в 10 раз), чем объявление области действия массива и обращение к каждому элементу для установки его значения.
К вашему сведению: я последовательно получаю более быстрые времена с первым циклом, который ведет обратный отсчет, при запуске этого в firebug (расширение firefox).
Мне интересно знать, что делает из этого TJ Crowder? :-)
источник
while (len--)
... приняв мое время обработки примерно с 60Я знал, что у меня где-то был этот прото :)
Редактировать: тесты
В ответ на Джошуа и другие методы я провел свой собственный сравнительный анализ и вижу результаты, совершенно отличные от тех, о которых сообщалось.
Вот что я проверял:
Результаты:
Так что, по моим расчетам, push действительно медленнее, но лучше работает с более длинными массивами в FF, но хуже в IE, который вообще отстой (в целом удивление).
источник
b = []...
) на 10-15% быстрее первого, но он более чем в 10 раз медленнее, чем ответ Джошуа.else {this.length=n;}
послеthis.length
-check. Это сократит уже существующий массив, если это необходимо, при повторнойinit
его настройке на другую длинуn
.Анонимная функция:
Немного короче с for-loop:
Работает с любым
Object
, просто поменяй что внутриthis.push()
.Вы даже можете сохранить функцию:
Позвоните, используя:
Добавление элементов в уже существующий массив:
Производительность: http://jsperf.com/zero-filled-array-creation/25
источник