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


1163

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

var foo = [];

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

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


224
Прочитав всю эту страницу, я пришел к выводу, что ваш собственный простой цикл for является самым простым, наиболее читаемым и наименее подверженным ошибкам.
Кокодоко

Если кому-то нужно что-то более продвинутое, я создал библиотеку node.js, которая делает это для чисел, букв, отрицательных / положительных диапазонов и т . Д. Github.com/jonschlinkert/fill-range . Он используется в github.com/jonschlinkert/braces для расширения фигурных скобок и github.com/jonschlinkert/micromatch для шаблонов
глобуса

1
Вы должны отредактировать, чтобы сказать «Как создать массив длины N» вместо «... содержащий 1 ... N», последнее подразумевает, что будут элементы со значениями от 1 до N
Стивен Лэндоу

7
@StevenLandow, почему ОП следует переименовывать? Он хочет массив со значениями 1 ... N?
Андре Элрико

Хороший вопрос, хорошее название, (вроде) глупые ответы.
Bitterblue

Ответы:


382

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


4
под впечатлением вы сумели сформулировать мой вопрос лучше, чем я, вы действительно правы, так как поразмысливая, все, что мне нужно, это массив чисел, который я могу потом просмотреть :) Спасибо за ваш ответ.
Godders

147
@Godders: Если это то, что вы ищете, зачем вам массив? Простое, var n = 45;а затем цикл из 1..nбудет делать.
Касабланка

3
@Godders - Обратите внимание: если вы хотите уменьшить размер массива после его создания до длины M, просто используйте foo.length = M--- Информация об обрезке теряется. Посмотрите это в действии ==> jsfiddle.net/ACMXp
Питер Айтай

24
Я действительно не понимаю, почему в этом ответе даже есть положительные отзывы ... особенно, когда сам ОП соглашается, что в нескольких комментариях выше это не имеет никакого смысла, поскольку он мог это сделать var n = 45;.
plalx

73
@scunliffe: Обратите внимание, что new Array(45);это не «создает массив из 45 элементов» (в том же значении, что [undefined,undefined,..undefined]и). Это скорее "создает пустой массив с длиной = 45" ( [undefined x 45]), так же, как var foo = []; foo.length=45;. Именно поэтому forEachи mapне будет применяться в этом случае.
tomalec

1311

В ES6 используются методы Array from () и 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]

75
Просто обратите внимание, это всегда будет начинаться с 0. Нужно будет связать a mapс массивом, чтобы скорректировать значения ( [...Array(10).keys()].map(x => x++);), чтобы начать с 1
Sterling Archer

33
Только изменения map(x => x++)в map(x => ++x)связи с приращением старшинства происходит после возвращения значения :)
Брок

94
Э, что? Почему mapкогда можно просто slice? [...Array(N+1).keys()].slice(1)
Робин

19
Или не используйте keysи только 1 карту ->Array.from(Array(10)).map((e,i)=>i+1)
yonatanmn

60
Или не используйте ключи и карту и просто передайте функцию сопоставленияfrom Array.from(Array(10), (e,i)=>i+1)
Fabio Antunes

845

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

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,5577575915358745, 0,5577581530874532, 0,17617830308732

объяснение

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

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

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

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

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


62
+1 для ловкости, но, пожалуйста, обратите внимание, что это на порядки МЕДЛЕННО, чем примитив для цикла: jsperf.com/array-magic-vs-for
warpech

7
Очень умно - наверное, тоже так. Используя тот факт, чтоFunction.prototype.call первый параметр является thisобъектом, отображаемым непосредственно через Array.prototype.mapпараметр итератора, имеет определенный блеск.
Ноа Фрейтас

14
Это действительно очень умно (граничит со злоупотреблением JS). По-настоящему важным моментом здесь является идиосинкразияmap моему, о неназначенных ценностях. Другая версия (и, возможно, немного яснее, хотя и дольше): Array.apply(null, { length: N }).map(function(element, index) { return index; })
Бен Райх,

6
@BenReich Еще лучше (с точки зрения уровней злоупотребления JS): Array.apply(null, new Array(N)).map(function(_,i) { return i; }) или, в случае функций es6 и стрелок, еще короче: Array.apply(null, new Array(N)).map((_,i) => i)
oddy

1
ЕСЛИ это возвращает массив, который начинается с 1, это фактически ответило бы на вопрос ОП
Sarsaparilla

484

Несколько способов использования ES6

Использование оператора распространения ( ...) и метода ключей

[ ...Array(N).keys() ].map( i => i+1);

Заливка / Карта

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

Array.from

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

Array. От и { length: N }взломать

Array.from({ length: N }, (_, i) => i+1)

Примечание об обобщенной форме

Все формы могут выдавать массивы инициализируются в значительной степени любых требуемых значения, изменяя i+1для выражения требуемого (например i*2, -i, 1+i*2,i%2 и т.д.). Если выражение может быть выражено некоторой функцией, fтогда первая форма становится просто

[ ...Array(N).keys() ].map(f)

Примеры:

Array.from({length: 5}, (v, k) => k+1); 
// [1,2,3,4,5]

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

Пример демонстрации всех форм

Более общий пример с пользовательской функцией инициализатора, fт.е.

[ ...Array(N).keys() ].map((i) => f(i))

или даже проще

[ ...Array(N).keys() ].map(f)


33
Лучший ответ ИМХО. Смотрите также developer.mozilla.org/de/docs/Web/JavaScript/Reference/...
le_m

5
Используйте k ++ для массивов, начинающихся с 0
Borgboy

1
Если вы хотите увеличить, не используйте k++, используйте ++k.
Alex

4
Остерегайтесь Array.from не поддерживается в IE, если вы не заполняете его.
Лорен

2
Чтобы сделать компилятор TS счастливым, рассмотрите возможность замены неиспользуемого параметра на lodash: Array.from ({length: 5}, (_, k) => k + 1);
Journeycorner

297

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



Вместо комментариев и путаницы, если вы действительно хотите получить значения из 1..N в приведенных выше примерах, есть несколько вариантов:

  1. если индекс доступен, вы можете просто увеличить его на единицу (например, ++i).
  2. в случаях, когда индекс не используется - и, возможно, более эффективный способ - это создать свой массив, но сделать N равным N + 1, а затем сдвинуться вперед.

    Итак, если вы хотите 100 номеров:

    let arr; (arr=[ ...Array(101).keys() ]).shift()





Я считаю, что это полезно, когда массив чисел используется для данных, которые не могут быть обработаны на принимающей стороне. (Как шаблон HTML, который просто заменяет значения.)
Нил Монро

Почему кто-то может сделать это, чтобы иметь массив чисел для заполнения выпадающего списка, предоставляя пользователю выбор от 1 до 10. Небольшой массив вручную [1,2,3 ... 10] имеет смысл, но что если это от 1 до 50? Что если конечный номер изменится?
CigarDoug

@CigarDoug Я не сомневаюсь, что есть сценарий использования, но я думаю, что он маленький. Зачем нужен массив чисел, обычно при итерации по массиву индекс будет использоваться как часть конструкции цикла - либо в качестве аргумента для функции тела цикла, либо в качестве переменной счетчика - поэтому удержание массива чисел кажется тривиальным просто создать массив указанной ширины или просто переменную, которая содержит верхнюю границу массива. Я могу вспомнить несколько случаев использования, но ни один из них не был
изложен

4
Как я уже сказал, мне нужно заполнить выпадающий список номерами от 1 до 10. Вот и все. Есть вариант использования, мой вариант использования. Вот как я нашел эту страницу. Поэтому создание массива вручную было менее сложным, чем все, что я видел здесь. Так что мои требования не являются требованиями ОП. Но у меня есть мой ответ.
CigarDoug

1
@ vol7ron Есть вариант использования, у меня тоже есть. В угловых, в подкачке, я хочу показать страницы в нижнем колонтитуле, которые являются кликабельными. Поэтому я зацикливаю элементы в представлении с помощью * ngFor = "let p of pagesCounter". У вас есть лучшее решение для этого? Кстати, посмотрите на stackoverflow.com/questions/36354325/…
Далибор

186

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

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

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

Edit: Изменен Array(45)в Array(N)виду того что вы обновили вопрос.

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


3
+1 , потому что это целая большая O лучше , чем неприятные .join.splitверсии - но я до сих пор считаю , что скромный цикл лучше.
Робин

Я согласен @Robin - Помимо алгоритмической сложности, скромный цикл всегда более читабелен. Однако, с появлением лямбд в Java, я думаю map, скоро станет стандартом для таких вещей.
Nate

4
const gen = N => [...(function*(){let i=0;while(i<N)yield i++})()]
Робин

8
Я не понимаю, зачем .fill()это нужно. Я вижу, что это когда я тестирую на узле repl, но с тех пор Array(1)[0] === undefined, какая разница в вызове fill () в Array(1).fill(undefined)make?
Доминик,

11
Для всех, кто интересуется, разница между Array (N) и Array (N) .fill () хорошо объяснена здесь
Доминик

108

Используйте очень популярный метод Underscore _.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); // => []


Потрясающие. Покажите мне большой проект, который в любом случае не использует подчеркивание ...
Эрез Коэн

63
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;
}

2
Мне это нравится. Если вы хотите пройти лишнюю милю с этим, вы можете объявить его как Array.prototype.range = function (start, end) {...} ;. Затем вы можете вызвать range (x, y) для любого объекта Array.
Зак Раттнер

8
Скорее всего сделать это метод Arrayвместо того , Array.prototypeтак как нет никакой причины (это может даже считать довольно тупой) , чтобы этот метод на каждом массиве.
Adamse

9
Array.range(1, 5)было бы, вероятно, более подходящим, но есть что-то классное в написании [].range(1, 5).
MooGoo

«Скорее сделайте это методом Array вместо Array.prototype». Какая разница? Вы имеете в виду только на конкретном массиве?
плов

3
@pilau Как говорит Адамс, это выглядит странно. Если это на прототипе, вы можете сказать foo = [1, 2, 3]; bar = foo.range(0, 10);. Но это просто ... сбивает с толку. bar = Array.range(0, 10)намного яснее и понятнее. Диапазон не имеет ничего общего с экземпляром, поэтому нет причин делать его методом экземпляра.
Ян Генри

53

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

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

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


есть ли способ сделать это без дополнительной переменной _
bluejayke

@bluejayke нет :(
алекс дыкіі

сурово, вы знаете, что такое исходный код .map? Я не уверен, что это быстрее, чем цикл for, но если нет, то теоретически мы можем просто определить свойство и создать новый
bluejayke

49

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

[...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
);


Итак, с вышеуказанной функцией вышеупомянутая супер-медленная «простая однострочная» становится супер-быстрой, даже более короткой:

range(1,14000);

@JVG, но не для более быстрой функции?
блюджайке

Абсолютно верно. Это тот простой лайнер, который все ищут!
supersan

@supersan, хотя это очень медленно :)
bluejayke

Современный javascript с новым fillметодом:Array(255).fill(0,0,255)
cacoder

@cacoder, как быстро, сколько массивов он создает и сколько итераций?
блюджайке

42

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

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]

Кроме того, почему нет new Array(10).join().split(',').map(function() {return ++arguments[1]});?
супер

1
@Murplyx для некоторых случаев функция с аргументами внутри не будет оптимизирована движком JS (верно даже для V8, см. Jsperf.com/arguments-vs-array-argument/2 )
nktssh

4
Это интересное решение, но оно совершенно нецелесообразно - необходимость анализировать массив 3 раза (один раз join, один раз splitи один раз для того, что вы на самом деле хотите сделать) просто нехорошо - я знаю, что они, похоже, потеряли популярность по какой-то причине, но было бы гораздо лучше просто использовать старый добрый цикл !
Робин

42

ES6 это сделает свое дело:

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

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

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


5
на самом деле они попросили 1..N, а не 0..N-1
YakovL

1
да, [...Array(N + 1).keys()].slice(1)даст 1..N
Дэвид Г

По какой-то причине это решение не работает в приложении Production Version from Expo. [...Array(N + 1).keys()]этот код возвращает пустой массив, но только в рабочем режиме, используя режим разработки, работает.
FabianoLothor

3
.keys()Ответ был уже дан лет назад и имеет 500+ upvotes. Что ваш ответ добавляет к этому?
Дан Даскалеску

39

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

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


Этот комментарий дал мне идею найти функцию range () в RamdaJS, которая является библиотекой JS, с которой я работаю над моим текущим проектом. Отлично.
морфический


38

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

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

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]

8
Было бы лучше подкрепить эти утверждения контрольными показателями. Попробуйте jsperf.com .
Мэтт Болл

2
lol jsperf ... пожалуйста, Мэтт, просто потому, что вам не нравится мой ответ, прекратите опускать голоса моих других ... stackoverflow.com/a/18344296/2450730 ... используйте console.time () или как он называется ... НЕ jsperf ,
Cocco

4
К вашему сведению: как Джон Рейзиг впервые опубликовал несколько лет назад - на некоторых платформах (то есть windows: P) время передается в браузер один раз каждые 16 мс. Также существуют другие проблемы с измерением времени выполнения в многозадачных средах. jsperf.com реализовал запуск тестов, чтобы они были статистически правильными. Это нормально, чтобы запустить console.time()интуицию, но для доказательства вам нужен jsperf.com, и он показывает результаты кроссбраузерного просмотра от других людей (различное оборудование и т. Д.)
naugtur

3
@cocco это неверно:var a=[],b=N;while(b--){a[b]=a+1};
vintagexav

5
@ cocco - хотя не всегда быстрее, чем другие петли. В некоторых браузерах уменьшающий цикл while намного медленнее цикла for, вы не можете делать общие заявления о производительности javascript, потому что существует так много реализаций с таким большим количеством различных оптимизаций. Однако в целом мне нравится ваш подход. ;-)
RobG

32

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

_.range([start=0], end, [step=1])

Создает массив чисел (положительных и / или отрицательных), начиная от начала до, но не включая конец. Шаг -1 используется, если указано отрицательное начало без конца или шага. Если end не указан, он запускается с start, затем устанавливается на 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);
// ➜ []

32

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

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

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


Это действительно хороший ответ, хотя технически вопрос был от 1-N, а не от 0- (N-1)
bluejayke

30

с 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)

Поскольку значения массива фактически заполнены с использованием этого решения, mapи forEachбудут работать.
dontmentionthebackup

27

Итоговый итоговый отчет. 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()]

Почему голосование за? Длинный список ответов трудно проследить, поэтому подумал о подведении итогов.
Сапи

это не 0-10? [... Array (10) .keys ()]
Грег

Webstorm предлагает (новый Array (10)). Keys (), правильно?
Парень

(new Array (10)). keys (), возвращает ArrayIterator {}, а не массив
sapy

Это создает глобальную переменную a. Цикл должен бытьfor(var a=[];n--;a[n]=n+1)
куб

20

В 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")


Эй, это аккуратно, мне это нравится. Однако он не возвращает результаты, которых ожидает ОП. Для этого его нужно записать какArray.from({length:N}, (v,i) => i+1)
CervEd 22.10.16


16

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

Заполняя отверстия undefined:

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

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

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

7
Кроме того , вы также можете сделать следующее в ES6: Array.from({length: N}, (v, k) => k).
XåpplI'-I0llwlg'I -

Подход Xappli предпочтителен: Array.from был создан почти для этого точного сценария и подразумевает обратный вызов сопоставления. Это отличное решение для общей проблемы желания использовать методы Array для чего-то похожего на массив, не прибегая к подробным подходам, таким как Array.prototype.map.call, например, для NodeLists, возвращаемых из document.querySelectorAll. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Джош из Карибу

Я взвешиваю это против синтаксиса диапазона подчеркивания, и диапазон читается лучше.
ооолала

Технически это не то, Array.fromчто превращает разреженные значения в неопределенные. Скорее Array(5)вызывается как объект аргументов, который в свою очередь интерпретирует разреженные значения как неопределенные значения :)
CervEd 22.10.16



12

В ES6:

Array.from({length: 1000}, (_, i) => i);

ES5:

Array.apply(0, {length: 1000}).map(function(x,i){return i});

10

Просто еще одна версия 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);


Это сложнее и примерно в 10 раз медленнее [...Array(11).keys()].slice(1).
Дан Даскалеску

10

Похоже, что единственной разновидностью, которой нет в этом довольно полном списке ответов, является вариант с генератором; так, чтобы исправить это:

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

И вместо того, чтобы что-то длительное эксплуатационно дорого, как:

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

10

Вы можете использовать Array fill и map из Es6; так же, как некоторые люди предложили в ответах на этот вопрос. Ниже приведено несколько примеров:

Example-One: Array(10).fill(0).map((e,i)=>i+1)

Result-One: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Example-Two: Array(100/10).fill(0).map((e,i)=>(i*10)+10)

Result-Two:[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

Я предпочитаю это, потому что нахожу это прямым и легким.



9

Использование ES6

const generateArray = n => [...Array(n)].map((_, index) => index + 1);

Спасибо! Это был самый элегантный ответ на мой взгляд! Можно также использовать, Array.from(Array(n))если оператор распространения не поддерживается.
Амит

Сначала я не знал, почему вы должны использовать оператор распространения, но затем я прочитал следующее о mapMDN : «Он не вызывается для отсутствующих элементов массива (то есть индексов, которые никогда не были установлены, которые имеют были удалены или которым никогда не было присвоено значение). "
battmanz

9

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] и сопоставьте ключи, преобразовав строки в числа.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.