Как создать массив, содержащий 1... N

Я ищу альтернативы ниже для создания массива JavaScript, содержащего от 1 до N, где N известно только во время выполнения.

var foo = [];

for (var i = 1; i <= N; i++) {
   foo.push(i);
}

Мне кажется, что должен быть способ сделать это без цикла.

Ответ 1

Если я получу то, что вам нужно, вам понадобится массив чисел 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/

Ответ 2

В 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]

Ответ 3

Вы можете сделать это:

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)? В конце концов, оба выражения приведут к массиву N элементов из элементов undefined. Разница в том, что в первом выражении каждый элемент явно установлен в undefined, тогда как в последнем каждый элемент никогда не был установлен. Согласно документации .map():

callback вызывается только для индексов массива, которым присвоены значения; он не вызывается для индексов, которые были удалены или которые никогда не были назначены значения.

Следовательно, Array(N) недостаточно; Array(N).map(Number.call, Number) приведет к неинициализированному массиву длины N.

Совместимость

Поскольку этот метод основан на поведении Function.prototype.apply(), указанном в ECMAScript 5, он будет не работать в браузерах до ECMAScript 5, таких как Chrome 14 и Internet Explorer 9.

Ответ 4

Простой и краткий путь в 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]

Поскольку массив инициализируется с undefined на каждой позиции, значение v будет undefined

const range = (N) => Array.from({length: N}, (v, k) => k+1) ;

console.log(
  range(5)
)

Ответ 5

Массивы изначально управляют своей длиной. По мере их прохождения их индексы могут храниться в памяти и ссылаться в этой точке. Если необходимо знать случайный индекс, можно использовать метод 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

распространение

Использование оператора распространения (...) и метода keys позволяет вам создать временный массив размера N для создания индексов, а затем новый массив, который можно назначить вашей переменной:

var foo = [ ...Array(N).keys() ];

Заполните/Карта

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

var foo = Array(N).fill().map((v,i)=>i);

Array.from

Это должно быть инициализация до длины размера N и заполнение массива за один проход.

Array.from({ length: N }, (v, i) => i)

Ответ 6

В ES6 вы можете:

Array(N).fill().map((e,i)=>i+1);

http://jsbin.com/molabiluwa/edit?js,console

Изменение: Изменен Array(45) до Array(N) так как вы обновили вопрос.

console.log(
  Array(45).fill(0).map((e,i)=>i+1)
);

Ответ 7

Используйте очень популярный метод подчёркивания _.range

// _.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); // => []

Ответ 8

function range(start, end) {
    var foo = [];
    for (var i = start; i <= end; i++) {
        foo.push(i);
    }
    return foo;
}

Затем вызывается

var foo = range(1, 5);

В Javascript нет встроенного способа сделать это, но это совершенно правильная функция полезности для создания, если вам нужно сделать это более одного раза.

Изменить: На мой взгляд, следующая лучшая функция диапазона. Возможно, только потому, что я склонен к 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;
}

Ответ 9

самый быстрый способ заполнить Array в v8:

[...Array(5)].map((_,i) => i);

результат будет: [0, 1, 2, 3, 4]

Ответ 10

На этот вопрос много сложных ответов, но простая однострочная:

[...Array(255).keys()].map(x => x + 1)

Кроме того, хотя вышеприведенный текст является коротким (и аккуратным) для написания, я думаю, что следующий текст немного быстрее (для максимальной длины:

127, Int8,

255, Uint8,

32,767, Int16,

65 535, Uint16,

2,147,483,647, Int32,

4,294,967,295, Uint32.

(основано на максимальных целочисленных значениях), также здесь больше о Typed Arrays):

(new Uint8Array(255)).map(($,i) => i + 1);

Хотя это решение также не является идеальным, поскольку оно создает два массива и использует дополнительное объявление переменной "$" (не уверен, что это можно обойти, используя этот метод). Я думаю, что следующее решение - абсолютно быстрый способ сделать это:

for(var i = 0, arr = new Uint8Array(255); i < arr.length; i++) arr[i] = i + 1;

В любое время после выполнения этого оператора вы можете просто использовать переменную "arr" в текущей области видимости;

Если вы хотите сделать из него простую функцию (с некоторой базовой проверкой):

function range(min, max) {
    min = min && min.constructor == Number ? min : 0;
    !(max && max.constructor == Number && max > min) && // boolean statements can also be used with void return types, like a one-line if statement.
        ((max = min) & (min = 0));  //if there is a "max" argument specified, then first check if its a number and if its graeter than min: if so, stay the same; if not, then consider it as if there is no "max" in the first place, and "max" becomes "min" (and min becomes 0 by default)

    for(var i = 0, arr = new (
        max < 128 ? Int8Array : 
        max < 256 ? Uint8Array :
        max < 32768 ? Int16Array : 
        max < 65536 ? Uint16Array :
        max < 2147483648 ? Int32Array :
        max < 4294967296 ? Uint32Array : 
        Array
    )(max - min); i < arr.length; i++) arr[i] = i + min;
    return arr;
}



//and you can loop through it easily using array methods if you want
range(1,11).forEach(x => console.log(x));

//or if you're used to pythons 'for...in' you can do a similar thing with 'for...of' if you want the individual values:
for(i of range(2020,2025)) console.log(i);

//or if you really want to use 'for..in', you can, but then you will only be accessing the keys:

for(k in range(25,30)) console.log(k);

console.log(
    range(1,128).constructor.name,
    range(200).constructor.name,
    range(400,900).constructor.name,
    range(33333).constructor.name,
    range(823, 100000).constructor.name,
    range(10,4) // when the "min" argument is greater than the "max", then it just considers it as if there is no "max", and the new max becomes "min", and "min" becomes 0, as if "max" was never even written
);

Ответ 11

Вы можете использовать это:

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]

Ответ 12

Если вы используете 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]

Ознакомьтесь с этот учебник для получения дополнительной информации.

Ответ 13

ES6 это сделает трюк:

[...Array(12).keys()]

проверьте результат:

[...Array(12).keys()].map(number => console.log(number))

Ответ 14

Это, вероятно, самый быстрый способ создания массива чисел

самый короткий

var a=[],b=N;while(b--)a[b]=b+1;

В соответствии

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]

ЗАЧЕМ?

  1. while самая быстрая петля

  2. Прямая настройка быстрее, чем push

  3. [] быстрее new Array(10)

  4. это коротко... посмотри первый код. тогда посмотрите на все остальные функции здесь.

Если вы хотите жить не может без для

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]

Ответ 15

Использование оператора распространения ES2015/ES6

[...Array(10)].map((_, i) => i + 1)

console.log([...Array(10)].map((_, i) => i + 1))

Ответ 16

Если вы используете lodash, вы можете использовать _. range:

_.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);
// ➜ []

Ответ 17

Новый способ заполнения Array:

const array = [...Array(5).keys()]
console.log(array)

Ответ 18

Итоговый отчет. Drrruummm Rolll -

Это кратчайший код для создания массива размера N (здесь 10) без использования ES6. Cocco версия выше близка, но не кратчайшая.

(function(n){for(a=[];n--;a[n]=n+1);return a})(10)

Но бесспорный победитель этого кодового гольфа (конкурс для решения конкретной проблемы в наименьших байтах исходного кода) Нико Руотсалайнен, Использование Array Constructor и оператора ES6 с расширением. (Большая часть синтаксиса ES6 действительна typeScript, но следующее - нет. Поэтому будьте осторожны при использовании)

[...Array(10).keys()]

Ответ 19

В ES6 есть еще один способ: Array.from, который принимает 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")

Ответ 20

Использование новых методов Array и => функциональный синтаксис из стандарта ES6 (только Firefox на момент написания).

Заполняя отверстия с помощью undefined:

Array(N).fill().map((_, i) => i + 1);

Array.from превращает "дырки" в undefined, поэтому Array.map работает так, как ожидалось:

Array.from(Array(5)).map((_, i) => i + 1)

Ответ 21

for(var i,a=[i=0];i<10;a[i++]=i);

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Ответ 22

Немного проще, чем строковый вариант:

// 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((v, i) => i + 1) // [1, 2, 3, 4, 5, 6, 7]

Обновление (04.01.2008): Обновлено для точного ответа на вопрос OP. Спасибо @lessless за это!

Ответ 23

Кажется, единственный вкус, который не в настоящее время находится в этом довольно полном списке ответов, - это один, в котором есть генератор; поэтому, чтобы исправить это:

const gen = N => [...(function*(){let i=0;while(i<N)yield i++})()]

который можно использовать таким образом:

gen(4) // [0,1,2,3]

Приятная вещь в этом - вам не просто нужно увеличивать... Чтобы вдохнуть в ответ ответ от @igor-shubin, вы могли бы легко создать массив рандомов:

const gen = N => [...(function*(){let i=0;
  while(i++<N) yield Math.random()
})()]

И чем-то longy оперативно дорого, например:

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

Ответ 24

Итерируемая версия с использованием функции генератора, которая не модифицирует 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)])

Ответ 25

с ES6 вы можете сделать:

// 'n' is the size you want to initialize your array
// 'null' is what the array will be filled with (can be any other value)
Array(n).fill(null)

Ответ 26

Еще одна версия ES6.

Используя Array.from второй необязательный аргумент:

Array.from(arrayLike [, mapFn [, thisArg]])

Мы можем построить нумерованный массив из пустых позиций Array(10):

Array.from(Array(10), (_, i) => i)

var arr = Array.from(Array(10), (_, i) => i);
document.write(arr);

Ответ 27

Попробуйте следующее:

var foo = [1, 2, 3, 4, 5];

Если вы используете CoffeeScript, вы можете создать диапазон, выполнив следующие действия:

var foo = [1..5]; 

В противном случае, если вы используете ванильный JavaScript, вам нужно будет использовать цикл, если вы хотите инициализировать массив до переменной длины.

Ответ 28

Следующая функция возвращает массив, заполненный числами:

var createArrayOfNumbers = function (n) {
    return Array.apply(null, new Array(n)).map(function (empty, index) {
        return index;
    });
};

Обратите внимание, что массив, созданный с помощью конструктора массива, состоит из отверстий, поэтому он не может быть перемещен с помощью функций массива, таких как map. Следовательно, используя функцию Array.apply.

Ответ 29

Array(8).fill(0).map(Number.call, Number)

Воровство Igors Number.call трюк, но с использованием fill(), чтобы немного сократить. Работает только с ES6 и выше.

Ответ 30

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] сделать массив итерабельным. Примечание: null более распространено в качестве применения первого аргумента, но 0 короче.
  • Object.keys(Array.apply(0,Array(3))) // ['0', '1', '2'] затем получить ключи массива (работает, потому что массивы типа type представляют собой объект с индексами для ключей.
  • Object.keys(Array.apply(0,Array(3))).map(Number) // [0, 1, 2] и сопоставить клавиши, преобразуя строки в числа.