Який найефективніший спосіб створити масив довільної довжини, заповненої нулем у JavaScript?
let i = 0; Array.from(Array(10), ()=>i++);
Який найефективніший спосіб створити масив довільної довжини, заповненої нулем у JavaScript?
let i = 0; Array.from(Array(10), ()=>i++);
Відповіді:
ES6 вводить Array.prototype.fill
. Його можна використовувати так:
new Array(len).fill(0);
Не впевнений, чи швидко це, але мені це подобається, оскільки він короткий і самоописується.
Це все ще не в IE ( перевірити сумісність ), але є поліфіл .
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 або там abouts ... тоді 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 центи. Не впевнений, наскільки це повільно / швидко, але це швидкий один лайнер. Ось що я роблю:
Якщо я хочу заздалегідь заповнити номер:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
// [0, 0, 0, 0, 0]
Якщо я хочу попередньо заповнити рядок:
Array.apply(null, Array(3)).map(String.prototype.valueOf,"hi")
// ["hi", "hi", "hi"]
Інші відповіді пропонують:
new Array(5+1).join('0').split('')
// ["0", "0", "0", "0", "0"]
але якщо ви хочете 0 (число), а не "0" (нуль всередині рядка), ви можете зробити:
new Array(5+1).join('0').split('').map(parseFloat)
// [0, 0, 0, 0, 0]
Array.apply(null, new Array(5)).map(...)
? Тому що просто робити (новий масив (5)). Карта (...) не працюватиме, як розповідає специфікація
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(Array(3), () => 0)
< [0, 0, 0]
Він працює, передаючи функцію карти як другий параметр Array.from
.
У наведеному вище прикладі перший параметр виділяє масив із 3-х позицій, заповнених значенням, undefined
а потім функція лямбда присвоює кожне з них значення 0
.
Хоча Array(len).fill(0)
це і коротше, він не працює, якщо вам потрібно заповнити масив, зробивши спочатку деякі обчислення (я знаю, що питання цього не задавав, але багато людей в кінцевому підсумку шукають цього) .
Наприклад, якщо вам потрібен масив з 10 випадковими числами:
> Array.from(Array(10), () => Math.floor(10 * Math.random()))
< [3, 6, 8, 1, 9, 3, 0, 6, 7, 1]
Це більш стисло (і елегантно), ніж еквівалент:
const numbers = Array(10);
for (let i = 0; i < numbers.length; i++) {
numbers[i] = Math.round(10 * Math.random());
}
Цей метод також може бути використаний для генерації послідовностей чисел, скориставшись параметром індексу, наданим у зворотному дзвінку
> Array.from(Array(10), (d, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
repeat()
Оскільки ця відповідь привертає багато уваги, я також хотів показати цей крутий трюк. Хоча не настільки корисний, як моя головна відповідь, введе досі не дуже відомий, але дуже корисний repeat()
метод String . Ось хитрість:
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
Класно, так? repeat()
є дуже корисним методом створення рядка, який є повторенням оригінальної рядки певну кількість разів. Після цього split()
створює для нас масив, який потім відповідає map()
значущим нам значенням. Розбивши його по кроках:
> "?".repeat(10)
< "??????????"
> "?".repeat(10).split("")
< ["?", "?", "?", "?", "?", "?", "?", "?", "?", "?"]
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
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)
- тому я навіть не буду оновлювати картину відьом у цьому випадку.
a = new Array(n); for (let i = 0; i < n; ++i) a[i] = 0;
. Тест
Уже згаданий метод заповнення ES 6 добре допомагає про це. Більшість сучасних настільних браузерів вже підтримують необхідні методи прототипу Array на сьогодні (Chromium, FF, Edge та Safari) [ 1 ]. Ви можете переглянути деталі на MDN . Простий приклад використання
a = new Array(10).fill(0);
З огляду на поточну підтримку веб-переглядача, ви повинні з обережністю використовувати це, якщо ви не впевнені, що ваша аудиторія використовує сучасні настільні браузери.
a = Array(10).fill(null).map(() => { return []; });
a = Array(10).fill(0).map( _ => [] );
Примітка додано в серпні 2013 року, оновлено лютий 2015 року: Відповідь нижче від 2009 року стосується загального Array
типу JavaScript . Це не стосується новіших набраних масивів, визначених у ES2015 [та доступних зараз у багатьох браузерах], таких як тощо Int32Array
. Також зауважте, що ES2015 додає fill
метод як для масивів, так і для набраних масивів , що, ймовірно, буде найефективнішим способом їх заповнення ...
Крім того, це може мати велике значення для деяких реалізацій того, як ви створюєте масив. Зокрема, двигун V8 Chrome намагається використовувати високоефективний масив пам’яті безперервної пам’яті, якщо він вважає, що може, переходячи на об’єктний масив лише за необхідності.
Для більшості мов було б попередньо виділити, а потім заповнити нуль, як це:
function newFilledArray(len, val) {
var rv = new Array(len);
while (--len >= 0) {
rv[len] = val;
}
return rv;
}
Але JavaScript масиви насправді не є масивами , вони є ключовими / цінними картами, як і всі інші об’єкти JavaScript, тому не потрібно робити «попереднього розподілу» (якщо довжина не виділяє стільки слотів для заповнення), ні чи є підстави вважати, що вигода від зворотного відліку до нуля (що полягає лише в тому, щоб зробити порівняння в циклі) швидко не переважає, додаючи ключі в зворотному порядку, коли реалізація цілком оптимізувала їх роботу з ключами пов'язані з масивами теорії, ти зазвичай робиш їх у порядку.
Насправді Меттью Крамлі зазначав, що підрахунок на Firefox помітно повільніше, ніж підрахунок, результат, який я можу підтвердити, - це частина масиву (циклічне зменшення до нуля все ж швидше, ніж циклічне відновлення до вару). Очевидно додавання елементів до масиву у зворотному порядку - це повільна опція для Firefox. Насправді, результати відрізняються від реалізації JavaScript (що не все дивно). Ось швидка та брудна тестова сторінка (внизу) для реалізацій браузера (дуже брудна, не піддається під час тестів, тому забезпечує мінімальний зворотній зв'язок і буде досягати часових обмежень сценарію). Я рекомендую поновитись між тестами; FF (принаймні) сповільнюється при повторних тестах, якщо ви цього не зробите.
Досить складна версія, яка використовує Array # concat, швидша, ніж прямий init на FF, приблизно десь між 1000 та 2000 масивами елементів. На двигуні V8 Chrome, однак, прямо-таки init виграє щоразу ...
Ось тестова сторінка (в реальному часі ):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Zero Init Test Page</title>
<style type='text/css'>
body {
font-family: sans-serif;
}
#log p {
margin: 0;
padding: 0;
}
.error {
color: red;
}
.winner {
color: green;
font-weight: bold;
}
</style>
<script type='text/javascript' src='prototype-1.6.0.3.js'></script>
<script type='text/javascript'>
var testdefs = {
'downpre': {
total: 0,
desc: "Count down, pre-decrement",
func: makeWithCountDownPre
},
'downpost': {
total: 0,
desc: "Count down, post-decrement",
func: makeWithCountDownPost
},
'up': {
total: 0,
desc: "Count up (normal)",
func: makeWithCountUp
},
'downandup': {
total: 0,
desc: "Count down (for loop) and up (for filling)",
func: makeWithCountDownArrayUp
},
'concat': {
total: 0,
desc: "Concat",
func: makeWithConcat
}
};
document.observe('dom:loaded', function() {
var markup, defname;
markup = "";
for (defname in testdefs) {
markup +=
"<div><input type='checkbox' id='chk_" + defname + "' checked>" +
"<label for='chk_" + defname + "'>" + testdefs[defname].desc + "</label></div>";
}
$('checkboxes').update(markup);
$('btnTest').observe('click', btnTestClick);
});
function epoch() {
return (new Date()).getTime();
}
function btnTestClick() {
// Clear log
$('log').update('Testing...');
// Show running
$('btnTest').disabled = true;
// Run after a pause while the browser updates display
btnTestClickPart2.defer();
}
function btnTestClickPart2() {
try {
runTests();
}
catch (e) {
log("Exception: " + e);
}
// Re-enable the button; we don't yheidl
$('btnTest').disabled = false;
}
function runTests() {
var start, time, counter, length, defname, def, results, a, invalid, lowest, s;
// Get loops and length
s = $F('txtLoops');
runcount = parseInt(s);
if (isNaN(runcount) || runcount <= 0) {
log("Invalid loops value '" + s + "'");
return;
}
s = $F('txtLength');
length = parseInt(s);
if (isNaN(length) || length <= 0) {
log("Invalid length value '" + s + "'");
return;
}
// Clear log
$('log').update('');
// Do it
for (counter = 0; counter <= runcount; ++counter) {
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
start = epoch();
a = def.func(length);
time = epoch() - start;
if (counter == 0) {
// Don't count (warm up), but do check the algorithm works
invalid = validateResult(a, length);
if (invalid) {
log("<span class='error'>FAILURE</span> with def " + defname + ": " + invalid);
return;
}
}
else {
// Count this one
log("#" + counter + ": " + def.desc + ": " + time + "ms");
def.total += time;
}
}
}
}
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
def.avg = def.total / runcount;
if (typeof lowest != 'number' || lowest > def.avg) {
lowest = def.avg;
}
}
}
results =
"<p>Results:" +
"<br>Length: " + length +
"<br>Loops: " + runcount +
"</p>";
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
results += "<p" + (lowest == def.avg ? " class='winner'" : "") + ">" + def.desc + ", average time: " + def.avg + "ms</p>";
}
}
results += "<hr>";
$('log').insert({top: results});
}
function validateResult(a, length) {
var n;
if (a.length != length) {
return "Length is wrong";
}
for (n = length - 1; n >= 0; --n) {
if (a[n] != 0) {
return "Index " + n + " is not zero";
}
}
return undefined;
}
function makeWithCountDownPre(len) {
var a;
a = new Array(len);
while (--len >= 0) {
a[len] = 0;
}
return a;
}
function makeWithCountDownPost(len) {
var a;
a = new Array(len);
while (len-- > 0) {
a[len] = 0;
}
return a;
}
function makeWithCountUp(len) {
var a, i;
a = new Array(len);
for (i = 0; i < len; ++i) {
a[i] = 0;
}
return a;
}
function makeWithCountDownArrayUp(len) {
var a, i;
a = new Array(len);
i = 0;
while (--len >= 0) {
a[i++] = 0;
}
return a;
}
function makeWithConcat(len) {
var a, rem, currlen;
if (len == 0) {
return [];
}
a = [0];
currlen = 1;
while (currlen < len) {
rem = len - currlen;
if (rem < currlen) {
a = a.concat(a.slice(0, rem));
}
else {
a = a.concat(a);
}
currlen = a.length;
}
return a;
}
function log(msg) {
$('log').appendChild(new Element('p').update(msg));
}
</script>
</head>
<body><div>
<label for='txtLength'>Length:</label><input type='text' id='txtLength' value='10000'>
<br><label for='txtLoops'>Loops:</label><input type='text' id='txtLoops' value='10'>
<div id='checkboxes'></div>
<br><input type='button' id='btnTest' value='Test'>
<hr>
<div id='log'></div>
</div></body>
</html>
За замовчуванням Uint8Array
, Uint16Array
і Uint32Array
класи тримати нулі її цінності, так що вам не потрібні ніякі складні методи наповнення, просто зробити:
var ary = new Uint8Array(10);
всі елементи масиву ary
за замовчуванням будуть нулями.
Array.isArray(ary)
є false
. Довжина також доступна лише для читання, тому ви не можете натискати на неї нові елементи, як це ary.push
0
як їх значення за замовчуванням.
Array.from(new Uint8Array(10))
забезпечить нормальний масив.
Array(n).fill(0)
у Chrome, якщо те, що вам потрібно, - це масив JS. Якщо ви можете використовувати TypedArray, це набагато швидше, ніж .fill(0)
, хоча, особливо якщо ви можете використовувати значення ініціалізатора за замовчуванням 0
. Здається, не існує конструктора, який приймає значення заповнення та довжину, як це std::vector
має C ++ . Здається, для будь-якого ненульового значення потрібно побудувати нульовий TypedArray і потім заповнити його. : /
Якщо ви використовуєте ES6, ви можете використовувати Array.from () так:
Array.from({ length: 3 }, () => 0);
//[0, 0, 0]
Має такий же результат, як і
Array.from({ length: 3 }).map(() => 0)
//[0, 0, 0]
Тому що
Array.from({ length: 3 })
//[undefined, undefined, undefined]
function makeArrayOf(value, length) {
var arr = [], i = length;
while (i--) {
arr[i] = value;
}
return arr;
}
makeArrayOf(0, 5); // [0, 0, 0, 0, 0]
makeArrayOf('x', 3); // ['x', 'x', 'x']
Зверніть увагу , що while
, як правило , більш ефективні , ніж for-in
, forEach
і т.д.
i
локальна змінна? length
передається за значенням, тому вам слід мати можливість декрементувати його безпосередньо.
arr[i] = value
) дуже повільно (наприклад ). Значно швидше пройти цикл від початку до кінця та використовувати arr.push(value)
. Це дратує, тому що я віддаю перевагу вашому методу.
використовуючи позначення об'єкта
var x = [];
нуль заповнений? подібно до...
var x = [0,0,0,0,0,0];
заповнене "невизначеним" ...
var x = new Array(7);
noj позначення з нулями
var x = [];
for (var i = 0; i < 10; i++) x[i] = 0;
Як бічна примітка, якщо ви модифікуєте прототип Array, обидва
var x = new Array();
і
var y = [];
буде мати ці модифікації прототипу
У будь-якому випадку, я не надто переймаюся ефективністю або швидкістю цієї операції, є багато інших речей, які ви, ймовірно, будете робити, набагато більш марно і дорого, ніж інстанціювати масив довільної довжини, що містить нулі.
null
у цьому масиві немає s -var x = new Array(7);
new Array(7)
це НЕ створює масив «наповнений невизначеним». Він створює порожній масив довжиною 7.
(new Array(10)).fill(0)
.
Я перевірив усі комбінації попереднього розподілу / не попереднього розподілу, підрахунку вгору / вниз, та циклів / для циклів в IE 6/7/8, Firefox 3.5, Chrome та Opera.
Функції нижче були послідовно найшвидшими або надзвичайно близькими у Firefox, Chrome та IE8, і не набагато повільніше, ніж найшвидші в Opera та IE 6. Це, на мій погляд, також найпростіший і зрозумілий. Я знайшов кілька браузерів, де версія циклу while трохи швидша, тому я включаю її також для довідки.
function newFilledArray(length, val) {
var array = [];
for (var i = 0; i < length; i++) {
array[i] = val;
}
return array;
}
або
function newFilledArray(length, val) {
var array = [];
var i = 0;
while (i < length) {
array[i++] = val;
}
return array;
}
var array = []
декларацію в першу частину циклу for 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 як змінну, видиму коду, який потребує нульових масивів:
var zero = newFilledArray(maxLength, 0);
Тепер відріжте цей масив щоразу, коли вам потрібен нульовий масив довжини, необхідноїLength < maxLength :
zero.slice(0, requiredLength);
Я створював масиви, заповнені нулями тисячі разів під час виконання мого коду, це надзвичайно прискорило процес.
Я нічого не маю проти:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
new Array(5+1).join('0').split('').map(parseFloat);
запропонований Zertosh, але в нових розширеннях масивів ES6 ви можете це зробити безпосередньо з fill
методом. Тепер IE edge, Chrome і FF підтримують його, але перевірте таблицю сумісності
new Array(3).fill(0)
дасть тобі [0, 0, 0]
. Ви можете заповнити масив будь-яким значеннямnew Array(5).fill('abc')
(наприклад, об'єктами та іншими масивами).
Крім того, ви можете змінювати попередні масиви із заповненням:
arr = [1, 2, 3, 4, 5, 6]
arr.fill(9, 3, 5) # what to fill, start, end
що дає вам: [1, 2, 3, 9, 9, 6]
Те, як я зазвичай це роблю (і це дивно швидко), використовує Uint8Array
. Наприклад, створення нульового заповненого вектора елементів 1М:
var zeroFilled = [].slice.apply(new Uint8Array(1000000))
Я користувач Linux і завжди працював для мене, але колись у друга, який використовував Mac, було кілька ненульових елементів. Я думав, що його машина несправна, але все-таки ось найбезпечніший спосіб, як ми її виправили:
var zeroFilled = [].slice.apply(new Uint8Array(new Array(1000000))
Відредаговано
Chrome 25.0.1364.160
Firefox 20.0
Не вистачає найважливішого тесту (принаймні для мене): Node.js. Я підозрюю, що це близько до еталону Chrome.
Використання лодашу або підкреслення
_.range(0, length - 1, 0);
Або якщо у вас є масив, який існує, і ви хочете масив однакової довжини
array.map(_.constant(0));
_.range(0, length, 0)
, я вважаю. Лодаш є ексклюзивним для кінцевого значення
Станом на ECMAScript2016 , існує великий вибір для великих масивів.
Оскільки ця відповідь все ще з’являється біля вершини в пошуку Google, ось відповідь за 2017 рік.
Ось поточний jsbench з кількома десятками популярних методів, включаючи безліч запропонованих до цього часу питань. Якщо ви знайдете кращий метод, будь ласка, додайте, розкладіть і поділіться.
Хочу зазначити, що не існує справжнього найефективнішого способу створення масиву заповненої довільною довжиною нуля. Ви можете оптимізувати швидкість чи чіткість та ремонтопридатність - або можна вважати більш ефективним вибором залежно від потреб проекту.
Оптимізуючи швидкість, ви хочете: створити масив, використовуючи буквальний синтаксис; встановіть довжину, ініціалізуйте змінну ітерації та повторіть масив, використовуючи цикл while. Ось приклад.
const arr = [];
arr.length = 120000;
let i = 0;
while (i < 120000) {
arr[i] = 0;
i++;
}
Іншою можливою реалізацією буде:
(arr = []).length = n;
let i = 0;
while (i < n) {
arr[i] = 0;
i++;
}
Але я настійно не рекомендую використовувати цю другу імплантацію на практиці, оскільки вона менш зрозуміла і не дозволяє підтримувати обсяг блоку на змінній масиву.
Вони значно швидше, ніж заповнення циклом for, і приблизно на 90% швидше, ніж стандартний метод
const arr = Array(n).fill(0);
Але цей метод заповнення все ще є найбільш ефективним вибором для менших масивів через його чіткість, стислість та ремонтопридатність. Різниця в продуктивності, швидше за все, не вб'є вас, якщо ви не зробите безліч масивів із довжиною порядку тисяч і більше.
Ще кілька важливих приміток. Більшість посібників зі стилів рекомендують більше не використовувати var
без особливих причин під час використання ES6 або новіших версій. Використовуйте const
для змінних, які не будуть переглянуті, і let
для змінних, які будуть. MDN і керівництво Стилю AirBnB в великих містах , щоб піти для отримання більш докладної інформації про передовий практиці. Питання полягало не в синтаксисі, але важливо, щоб люди, які не знають про JS, знали про ці нові стандарти під час пошуку цих витоків старих і нових відповідей.
Для створення всього нового масиву
new Array(arrayLength).fill(0);
Щоб додати деякі значення в кінці наявного масиву
[...existingArray, ...new Array(numberOfElementsToAdd).fill(0)]
//**To create an all new Array**
console.log(new Array(5).fill(0));
//**To add some values at the end of an existing Array**
let existingArray = [1,2,3]
console.log([...existingArray, ...new Array(5).fill(0)]);
Не бачив цей метод у відповідях, тому ось він:
"0".repeat( 200 ).split("").map( parseFloat )
У результаті ви отримаєте нульовий масив довжиною 200:
[ 0, 0, 0, 0, ... 0 ]
Я не впевнений у ефективності цього коду, але це не повинно бути проблемою, якщо ви використовуєте його для відносно невеликих масивів.
const arr = Array.from({ length: 10 }).fill(0)
Ця concat
версія набагато швидша в моїх тестах на Chrome (2013-03-21). Близько 200 мс для 10 000 000 елементів проти 675 для прямого init.
function filledArray(len, value) {
if (len <= 0) return [];
var result = [value];
while (result.length < len/2) {
result = result.concat(result);
}
return result.concat(result.slice(0, len-result.length));
}
Бонус: якщо ви хочете заповнити свій масив Strings, це стислий спосіб зробити це (не так швидко, як concat
би):
function filledArrayString(len, value) {
return new Array(len+1).join(value).split('');
}
Я випробовував чудову відповідь TJ Crowder і придумав рекурсивне злиття на основі лаконічного рішення, яке перевершує будь-які його тести в Chrome (я не перевіряв інших браузерів).
function makeRec(len, acc) {
if (acc == null) acc = [];
if (len <= 1) return acc;
var b = makeRec(len >> 1, [0]);
b = b.concat(b);
if (len & 1) b = b.concat([0]);
return b;
},
викликати метод за допомогою makeRec(29)
.
Можливо, варто зазначити, що Array.prototype.fill
це було додано як частина пропозиції ECMAScript 6 (Гармонія) . Я б скоріше пішов із написаним нижче поліфілом, перш ніж розглядати інші варіанти, згадані на потоці.
if (!Array.prototype.fill) {
Array.prototype.fill = function(value) {
// Steps 1-2.
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
// Steps 3-5.
var len = O.length >>> 0;
// Steps 6-7.
var start = arguments[1];
var relativeStart = start >> 0;
// Step 8.
var k = relativeStart < 0 ?
Math.max(len + relativeStart, 0) :
Math.min(relativeStart, len);
// Steps 9-10.
var end = arguments[2];
var relativeEnd = end === undefined ?
len : end >> 0;
// Step 11.
var final = relativeEnd < 0 ?
Math.max(len + relativeEnd, 0) :
Math.min(relativeEnd, len);
// Step 12.
while (k < final) {
O[k] = value;
k++;
}
// Step 13.
return O;
};
}
Найкоротший код циклу
a=i=[];for(;i<100;)a[i++]=0;
edit:
for(a=i=[];i<100;)a[i++]=0;
or
for(a=[],i=100;i--;)a[i]=0;
Безпечна версія версії
var a=[],i=0;for(;i<100;)a[i++]=0;
edit:
for(var i=100,a=[];i--;)a[i]=0;
n
це буде коротше:for(var a=[];n--;a[n]=0);
let filled = [];
filled.length = 10;
filled.fill(0);
console.log(filled);
Моя найшвидша функція:
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
var st = (new Date()).getTime();
newFilledArray(1000000, 0)
console.log((new Date()).getTime() - st); // returned 63, 65, 62 milliseconds
Використання нативного натискання та зсуву для додавання елементів до масиву набагато швидше (приблизно в 10 разів), ніж оголошення області масиву та посилання кожного елемента для встановлення його значення.
fyi: я постійно отримую швидші часи з першим циклом, який відлічується під час запуску цього в firebug (розширення firefox).
var a = [];
var len = 1000000;
var st = (new Date()).getTime();
while(len){
a.push(0);
len -= 1;
}
console.log((new Date()).getTime() - st); // returned 863, 894, 875 milliseconds
st = (new Date()).getTime();
len = 1000000;
a = [];
for(var i = 0; i < len; i++){
a.push(0);
}
console.log((new Date()).getTime() - st); // returned 1155, 1179, 1163 milliseconds
Мені цікаво знати, що з цього робить TJ Crowder? :-)
while (len--)
.., зайняв час обробки приблизно від 60 мс до приблизно 54 мс
Я знав, що у мене цей протод десь :)
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
var a = (new Array(5)).init(0);
var b = [].init(0,4);
Редагувати: тести
У відповідь на Джошуа та інші методи я здійснив власний бенчмаркінг, і я бачу зовсім інші результати від тих, про які повідомлялося.
Ось що я перевірив:
//my original method
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
//now using push which I had previously thought to be slower than direct assignment
Array.prototype.init2 = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this.push(x); }
return this;
}
//joshua's method
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
//test m1 and m2 with short arrays many times 10K * 10
var a = new Date();
for(var i=0; i<10000; i++)
{
var t1 = [].init(0,10);
}
var A = new Date();
var b = new Date();
for(var i=0; i<10000; i++)
{
var t2 = [].init2(0,10);
}
var B = new Date();
//test m1 and m2 with long array created once 100K
var c = new Date();
var t3 = [].init(0,100000);
var C = new Date();
var d = new Date();
var t4 = [].init2(0,100000);
var D = new Date();
//test m3 with short array many times 10K * 10
var e = new Date();
for(var i=0; i<10000; i++)
{
var t5 = newFilledArray(10,0);
}
var E = new Date();
//test m3 with long array created once 100K
var f = new Date();
var t6 = newFilledArray(100000, 0)
var F = new Date();
Результати:
IE7 deltas:
dA=156
dB=359
dC=125
dD=375
dE=468
dF=412
FF3.5 deltas:
dA=6
dB=13
dC=63
dD=8
dE=12
dF=8
Так що, за моїм рахунком, поштовх дійсніше повільніше, але працює краще з довшими масивами у FF, але гірше в IE, який просто смокче загалом (quel сюрприз).
b = []...
) на 10-15% швидший, ніж перший, але в 10 разів повільніше, ніж відповідь Джошуа.
else {this.length=n;}
після this.length
-вивірку. Це дозволить скоротити вже наявний масив, якщо необхідно, повторний init
діапазон його на іншу довжину n
.
Анонімні функції:
(function(n) { while(n-- && this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
Трохи коротше з for-loop:
(function(n) { for(;n--;this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
Працює з будь-яким Object
, просто змінити те, що знаходиться всередині this.push()
.
Ви навіть можете зберегти функцію:
function fill(size, content) {
for(;size--;this.push(content));
return this;
}
Телефонуйте за допомогою:
var helloArray = fill.call([], 5, 'hello');
// => ['hello', 'hello', 'hello', 'hello', 'hello']
Додавання елементів до вже наявного масиву:
var helloWorldArray = fill.call(helloArray, 5, 'world');
// => ['hello', 'hello', 'hello', 'hello', 'hello', 'world', 'world', 'world', 'world', 'world']
Продуктивність: http://jsperf.com/zero-filled-array-creation/25