Создайте массив JavaScript, содержащий 1...N



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



var foo = [];

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


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

672   30  

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]

почему?

  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]

Примечание: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)
for(var i,a=[i=0];i<10;a[i++]=i);

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

попробуйте это:

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 и выше.

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

Comments

    Ничего не найдено.