Создайте массив JavaScript, содержащий 1...N
Я ищу любые альтернативы ниже для создания массива JavaScript, содержащего от 1 до N, где N известен только во время выполнения.
var foo = [];
for (var i = 1; i <= N; i++) {
foo.push(i);
}
Мне кажется, что там должен быть способ сделать это без цикла.
30 ответов:
Если я получу то, что вам нужно, вы хотите массив чисел
1..n, который впоследствии сможет перебрать.Если это все, что вам нужно, вы можете сделать вместо этого?
var foo = new Array(45);//create an empty array with length 45затем, когда вы хотите использовать его... (неоптимизированный, например)
for(var i=0;i<foo.length;i++){ document.write('Item: ' + (i+1) + ' of ' + foo.length + '<br/>'); }например, если вам не надо магазине что-нибудь в массиве, вам просто нужен контейнер правильной длины, который вы можете перебирать... это может быть проще.
посмотреть в действие здесь: http://jsfiddle.net/3kcvm/
можно сделать так:
var N = 10; Array.apply(null, {length: N}).map(Number.call, Number)результат: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
или случайными значениями:
Array.apply(null, {length: N}).map(Function.call, Math.random)результат: [0.7082694901619107, 0.9572225909214467, 0.8586748542729765, 0.8653848143294454, 0.008339877473190427, 0.9911756622605026, 0.8133423360995948, 0.8377588465809822, 0.5577575915958732, 0.16363654541783035]
объяснение
во-первых, обратите внимание, что
Number.call(undefined, N)эквивалентноNumber(N), который просто возвращаетN. Мы воспользуемся этим фактом позже.
Array.apply(null, [undefined, undefined, undefined])эквивалентноArray(undefined, undefined, undefined), который создает трехэлементный массив и присваиваетundefinedдля каждого элемента.как вы можете обобщить это на N элементов? Рассмотрим, как
Array()строительство, которое идет что-то вроде этого:function Array() { if ( arguments.length == 1 && 'number' === typeof arguments[0] && arguments[0] >= 0 && arguments && arguments[0] < 1 << 32 ) { return [ … ]; // array of length arguments[0], generated by native code } var a = []; for (var i = 0; i < arguments.length; i++) { a.push(arguments[i]); } return a; }Начиная С ECMAScript 5,
Function.prototype.apply(thisArg, argsArray)также принимает утка-типизированный массив-как объект как его второй параметр. Если мы вызовемArray.apply(null, { length: N }), то он будет выполнятьfunction Array() { var a = []; for (var i = 0; i < /* arguments.length = */ N; i++) { a.push(/* arguments[i] = */ undefined); } return a; }теперь у нас есть N-массив элементов, каждый из которых имеет значение
undefined. Когда мы зовем.map(callback, thisArg)на нем, каждый элемент будет установлен в результатеcallback.call(thisArg, element, index, array). Таким образом,[undefined, undefined, …, undefined].map(Number.call, Number)будет отображать каждый элемент в(Number.call).call(Number, undefined, index, array), что то же самое, чтоNumber.call(undefined, index, array), который, как мы уже отмечали ранее, оценивается вindex. Это завершает массив, элементы которого такие же, как их индекс.Зачем идти через трудности
Array.apply(null, {length: N})вместоArray(N)? В конце концов, оба выражения приведут к an N-элемент массива значение undefined элементов. Разница в том, что в первом выражении каждый элемент явно set к неопределенному, тогда как в последнем каждый элемент никогда не был установлен. Согласно документации.map():
callbackвызывается только индексы массива, которым присвоены значения; он не вызывается для индексов, которые были удалены или которым никогда не присваивались значения.таким образом,
Array(N)недостаточный;Array(N).map(Number.call, Number)приведет к неинициализированному массиву длины N.совместимость
так как этот метод основан на поведении
Function.prototype.apply(), указанный в ECMAScript 5, он будет не работает в браузерах до ECMAScript 5, таких как Chrome 14 и Internet Explorer 9.
в ES6 с помощью Array у() и keys () методы.
Array.from(Array(10).keys()) //=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]более короткая версия с помощью распространение оператор.
[...Array(10).keys()] //=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
простой и краткий путь в ES6:
Array.from({length: 5}, (v, k) => k+1); // [1,2,3,4,5]таким образом :
Array.from({length: N}, (v, k) => k+1); // [1,2,3,...,N]const range = (N) => Array.from({length: N}, (v, k) => k+1) ; console.log( range(5) )
в ES6 вы можете сделать:
Array(N).fill().map((e,i)=>i+1);http://jsbin.com/molabiluwa/edit?js, консоль
изменить: Изменилось
Array(45)доArray(N)так как вы обновили вопрос.console.log( Array(45).fill(0).map((e,i)=>i+1) );
используйте очень популярный подчеркивания _.метод диапазона
// _.range([start], stop, [step]) _.range(10); // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] _.range(1, 11); // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] _.range(0, 30, 5); // => [0, 5, 10, 15, 20, 25] _.range(0, -10, -1); // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] _.range(0); // => []
Я знаю, что ваш вопрос просит заполнить массив численно, но я не уверен, почему вы хотите это сделать.
массивы врожденно управляют своей длиной. По мере их обхода их индексы могут храниться в памяти и ссылаться на эту точку. Если случайный индекс должен быть известен,
indexOfметод может быть использован.
Тем не менее, для ваших нужд вы можете просто объявить массив определенного размера:var foo = new Array(N); // where N is a positive integer /* this will create an array of size, N, primarily for memory allocation, but does not create any defined values foo.length // size of Array foo[ Math.floor(foo.length/2) ] = 'value' // places value in the middle of the array */
ES6
распространение
использование оператора spread (
...) иkeysметод, позволяет создать временный массив размера N для получения индексов, а затем новый массив, который может быть назначен переменной:var foo = [ ...Array(N).keys() ];Заполнить/Карте
вы можете сначала создать размер массива, который вам нужен, заполнить его неопределенным, а затем создать новый массив с помощью
map, который задает каждый элемент к индексу.var foo = Array(N).fill().map((v,i)=>i);массив.от
это должно быть инициализация до длины размера N и заполнение массива за один проход.
Array.from({ length: N }, (v, i) => i)
function range(start, end) { var foo = []; for (var i = start; i <= end; i++) { foo.push(i); } return foo; }затем позвонил
var foo = range(1, 5);в Javascript нет встроенного способа сделать это, но это вполне допустимая функция утилиты для создания, если вам нужно сделать это более одного раза.
Edit: на мой взгляд, следующая функция лучше диапазона. Может быть, просто потому, что я предвзято отношусь к LINQ, но я думаю, что это более полезно в большем количестве случаев. Ваш пробег может отличаться.
function range(start, count) { if(arguments.length == 1) { count = start; start = 0; } var foo = []; for (var i = 0; i < count; i++) { foo.push(start + i); } return foo; }
вы можете использовать это:
new Array(/*any number which you want*/) .join().split(',') .map(function(item, index){ return ++index;})new Array(10) .join().split(',') .map(function(item, index){ return ++index;})создать следующий массив:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Если вы случайно используете d3.js в вашем приложении, как я, D3 предоставляет вспомогательную функцию, которая делает это за вас.
так, чтобы получить массив от 0 до 4, это так же просто, как:
d3.range(5) [0, 1, 2, 3, 4]и получить массив от 1 до 5, Как вы просили:
d3.range(1, 5+1) [1, 2, 3, 4, 5]проверить в этом уроке для получения дополнительной информации.
это, вероятно, самый быстрый способ создать массив чисел
короткий
var a=[],b=N;while(b--)a[b]=b+1;Inline
var arr=(function(a,b){while(a--)b[a]=a;return b})(10,[]); //arr=[0,1,2,3,4,5,6,7,8,9]если вы хотите начать с 1
var arr=(function(a,b){while(a--)b[a]=a+1;return b})(10,[]); //arr=[1,2,3,4,5,6,7,8,9,10]нужна функция?
function range(a,b,c){c=[];while(a--)c[a]=a+b;return c}; //length,start,placeholder var arr=range(10,5); //arr=[5,6,7,8,9,10,11,12,13,14]почему?
whileэто самый быстрый циклпрямая настройка выполняется быстрее, чем
push
[]это быстрее, чемnew Array(10)она короткая... посмотрите первый код. тогда посмотрите на все остальные функции здесь.
Если вам нравится не могу жить без на
for(var a=[],b=7;b>0;a[--b]=b+1); //a=[1,2,3,4,5,6,7]или
for(var a=[],b=7;b--;a[b]=b+1); //a=[1,2,3,4,5,6,7]Примечание:
apply,map,join-split.... срсли ??? это чертовски медленно!!!!!!а совместимость???
ES6 это будет делать трюк:
[...Array(12).keys()]проверить результат:
[...Array(12).keys()].map(number => console.log(number))
Если вы используете lodash, вы можете использовать _.диапазон:
_.range([start=0], end, [step=1])создает массив чисел (положительный и/или отрицательный) прогрессирование от запуска до, но не в том числе, и конец. Шаг 1 используется, если задано отрицательное начало без конца и шага. Если конец не задан, то он должен начаться с начнем значение 0.
примеры:
_.range(4); // ➜ [0, 1, 2, 3] _.range(-4); // ➜ [0, -1, -2, -3] _.range(1, 5); // ➜ [1, 2, 3, 4] _.range(0, 20, 5); // ➜ [0, 5, 10, 15] _.range(0, -4, -1); // ➜ [0, -1, -2, -3] _.range(1, 4, 0); // ➜ [1, 1, 1] _.range(0); // ➜ []
С помощью оператора ES2015 / ES6 spread
[...Array(10)].map((_, i) => ++i)console.log([...Array(10)].map((_, i) => ++i))
итоговый отчет .. Drrruummm Rolll -
Это короткий код чтобы сгенерировать массив размером N (здесь 10)без использования ES6. Coccoверсия выше близка, но не самая короткая.
(function(n){for(a=[];n--;a[n]=n+1);return a})(10)но бесспорным победителем из этого кода golf (конкурс для решения конкретной проблемы в наименьшем количестве байтов исходного кода) является Нико Руотсалайнен . Использование конструктора массива и ES6 spread operator . (Большая часть синтаксиса ES6 является допустимым typeScript, но следующее-Нет. Так что будьте благоразумны при его использовании)
[...Array(10).keys()]
есть еще один способ в ES6, используя массив.от который принимает 2 аргумента, первый является arrayLike (в этом случае объект с
lengthсвойство), а второй-функция отображения (в этом случае мы сопоставляем элемент с его индексом)Array.from({length:10}, (v,i) => i)Это короче и может быть использовано для других последовательностей, как генерация четных чисел
Array.from({length:10}, (v,i) => i*2)кроме того, это имеет лучшую производительность, чем большинство других способов, потому что он только петли один раз через массив. Регистрация скрипт для сравнения
// open the dev console to see results count = 100000 console.time("from object") for (let i = 0; i<count; i++) { range = Array.from({length:10}, (v,i) => i ) } console.timeEnd("from object") console.time("from keys") for (let i =0; i<count; i++) { range = Array.from(Array(10).keys()) } console.timeEnd("from keys") console.time("apply") for (let i = 0; i<count; i++) { range = Array.apply(null, { length: 10 }).map(function(element, index) { return index; }) } console.timeEnd("apply")
использование новых методов массива и
=>синтаксис функции из стандарта ES6 (только Firefox на момент написания).путем заполнять отверстия с
undefined:Array(N).fill().map((_, i) => i + 1);
Array.fromполучается "дыр" вundefinedтакArray.mapработает:Array.from(Array(5)).map((_, i) => i + 1)
попробуйте это:
var foo = [1, 2, 3, 4, 5];Если вы используете CoffeeScript, вы можете создать диапазон, выполнив:
var foo = [1..5];в противном случае, если вы используете ванильный JavaScript, вам придется использовать цикл, если вы хотите инициализировать массив до переменной длины.
следующая функция возвращает массив, заполненный числами:
var createArrayOfNumbers = function (n) { return Array.apply(null, new Array(n)).map(function (empty, index) { return index; }); };обратите внимание, что массив, созданный с помощью конструктора массива, состоит из отверстий, поэтому он не может быть пройден с помощью функций массива, таких как map. Следовательно, используя
немного проще, чем вариант строки:
// create range by N Array(N).join(0).split(0); // create a range starting with 0 as the value Array(7).join(0).split(0).map(Number.call, Number); // [0, 1, 2, 3, 4, 5, 6]
Object.keys(Array.apply(0, Array(3))).map(Number)возвращает
[0, 1, 2]. Очень похоже на отличный ответ Игоря Шубина, но с чуть меньшим количеством обмана (и одним символом дольше).объяснение:
Array(3) // [undefined × 3]создать массив длиной n=3. К сожалению, этот массив практически бесполезен для нас, поэтому мы должны...Array.apply(0,Array(3)) // [undefined, undefined, undefined]сделайте массив итерационным. Примечание: нуль более распространенными, а сначала обратиться в арг, но 0 это укорачиваться.Object.keys(Array.apply(0,Array(3))) // ['0', '1', '2']затем получить ключи массива (работает, потому что массивы являются typeof массив является объектом с индексами для ключей.Object.keys(Array.apply(0,Array(3))).map(Number) // [0, 1, 2]и карта над ключами, Преобразуя строки в числа.
просто еще один ES6 версия.
при использовании
Array.fromвторой необязательный аргумент:массив.от(arrayLike [, mapFn [, thisArg]])
мы можем построить нумерованный массив из пустого
Array(10)позиции:Array.from(Array(10), (_, i) => i)
var arr = Array.from(Array(10), (_, i) => i); document.write(arr);
кажется, что единственный аромат, который в настоящее время не находится в этом довольно полном списке ответов, - это генератор; поэтому чтобы исправить это:
const gen = N => [...(function*(){let i=0;while(i<N)yield i++})()]который можно использовать таким образом:
gen(4) // [0,1,2,3]хорошая вещь об этом вы не просто должны увеличить... Чтобы вдохновиться ответом @igor-shubin, вы можете очень легко создать массив randoms:
const gen = N => [...(function*(){let i=0; while(i++<N) yield Math.random() })()]а то
долгихоперативно дорого например:const slow = N => new Array(N).join().split(',').map((e,i)=>i*5) // [0,5,10,15,...]вы могли бы вместо этого сделать:
const fast = N => [...(function*(){let i=0;while(i++<N)yield i*5})()]
самый быстрый способ наполнения
Arrayв v8 это:[...Array(5)].map((_,i) => i)результат будет:
[0,1,2,3,4]
Я искал функциональное решение и я в конечном итоге с:
function numbers(min, max) { return Array(max-min+2).join().split(',').map(function(e, i) { return min+i; }); } console.log(numbers(1, 9));Примечание:
join().split(',')преобразует разреженный массив в непрерывный.
Импровизация на вышесказанное:
var range = function (n) { return Array(n).join().split(',').map(function(e, i) { return i; }); }можно получить следующие варианты:
1) массив.init для значения v
var arrayInitTo = function (n,v) { return Array(n).join().split(',').map(function() { return v; }); };2) получить обратный диапазон:
var rangeRev = function (n) { return Array(n).join().split(',').map(function() { return n--; }); };
Я не видел никакого решения, основанного на рекурсивных функциях (и никогда не писал рекурсивные функции сам), так что вот моя попытка.
обратите внимание на этот массив.push (something) возвращает новую длину массива:
(a=[]).push(a.push(a.push(0))) // a = [0, 1, 2]и с рекурсивной функцией:
var a = (function f(s,e,a,n){return ((n?n:n=s)>e)?a:f(s,e,a?a:a=[],a.push(n)+s)})(start,end) // e.g., start = 1, end = 5изменить: два других решения
var a = Object.keys(new Int8Array(6)).map(Number).slice(1)и
var a = [] var i=setInterval(function(){a.length===5?clearInterval(i):a.push(a.length+1)})
Array(8).fill(0).map(Number.call, Number)Воровать Игоры
Number.callтрюк, но с использованиемfill()немного укоротить. Работает только с ES6 и выше.
Comments