Создайте массив 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
затем, когда вы хотите использовать его... (un-optimized, например)
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)
также принимает массив типа duck объект как его второй параметр. Если мы призовем 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-массив элементов неопределенных элементов. Разница в том, что в первом выражении каждый элемент явно set в undefined, тогда как в последнем каждый элемент никогда не был установлен. Согласно документации .map()
:
callback
вызывается только индексы массива, которым присвоены значения; он не вызывается для индексов, которые были удалены или которым никогда не были присвоены значения.
таким образом, Array(N)
недостаточный; Array(N).map(Number.call, Number)
приведет к неинициализированному массиву длины N.
совместимость
поскольку этот метод основан на поведении Function.prototype.apply()
, указанный в ECMAScript 5, он будет не работает в браузерах pre-ECMAScript 5, таких как Chrome 14 и Internet Explorer 9.
в ES6 с использованием Array from () и ключи() методы.
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]
простой и краткий путь в ЕС6:
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)
to 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
*/
ЕС6
распространение
использование операторов (...
) и 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 используется, если задано отрицательное начало без конца и шага. Если end не указан, он настроен на запуск с начнем значение 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/ЕС6 распространение оператор
[...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 (конкуренция для решения конкретной проблемы в наименьшем количестве байтов исходного кода) является Нико Ruotsalainen . Используя конструктору Array ES6 оператор распространения . (Большая часть синтаксиса 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];
в противном случае, если вы используете vanilla 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]
создать массив типа Iterable. Примечание: null более распространен как первый arg apply, но 0 укорачиваться. -
Object.keys(Array.apply(0,Array(3))) // ['0', '1', '2']
затем получите ключи массива (работает, потому что массивы являются массивом typeof-это объект с индексами для ключей. -
Object.keys(Array.apply(0,Array(3))).map(Number) // [0, 1, 2]
и сопоставьте клавиши, Преобразуя строки в числа.
просто еще один ЕС6 версия.
при использовании 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
EDIT: два других решения
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 и выше.
типа Iterable версия с помощью генератор функция, которая не изменяет Number.prototype
.
function sequence(max, step = 1) {
return {
[Symbol.iterator]: function* () {
for (let i = 1; i <= max; i += step) yield i
}
}
}
console.log([...sequence(10)])