Як створити масив, що містить 1… N


1161

Я шукаю альтернативи нижче для створення масиву JavaScript, що містить від 1 до N, де N відомий лише під час виконання.

var foo = [];

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

Мені здається, що має бути спосіб зробити це без циклу.


224
Прочитавши всю цю сторінку, я прийшов до висновку, що ваш власний простий цикл for-loop - найпростіший, найчитабельніший і найменш схильний до помилок.
Кокодоко

Якщо комусь потрібно щось більш просунуте, я створив node.js lib, який робить це для цифр, літер, негативних / позитивних діапазонів тощо. Github.com/jonschlinkert/fill-range . Він використовується в github.com/jonschlinkert/braces для розширення дужок і github.com/jonschlinkert/micromatch для глобальних моделей
jonschlinkert

1
Вам слід відредагувати, щоб сказати "Як створити масив довжиною N" замість "... містить 1 ... N", останнє означає, що будуть елементи зі значеннями від 1 до N
Стівен Ландов

7
@StevenLandow Чому ОП слід перейменовувати? Він хоче масив зі значеннями 1 ... N?
Андре Елріко

Хороше запитання, хороший заголовок, (ніби) дурні відповіді.
Bitterblue

Відповіді:


381

Якщо я отримаю те, що ви шукаєте, ви хочете масив чисел, 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буде робити.
casablanca

3
@Godders - Щоб відзначити, якщо ви хочете зменшити розмір масиву після його створення до довжини M, просто використовуйте foo.length = M--- Зрізана інформація втрачається. Дивіться це в дії ==> jsfiddle.net/ACMXp
Peter Ajtai

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

72
@scunliffe: Зауважте, що new Array(45);не "створюється масив з 45 елементами" (в тому ж значенні, що [undefined,undefined,..undefined]і). Він швидше "створює порожній масив довжиною = 45" ( [undefined x 45]), такий же, як var foo = []; foo.length=45;. Ось чому forEach, і mapне буде застосовуватися в цьому випадку.
tomalec

1307

В ES6 використовують Array від () та ключів () методів.

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]

74
Лише зауважте, це завжди буде починатися з 0. Потрібно буде ланцюг a mapдо масиву, щоб відкоригувати значення ( [...Array(10).keys()].map(x => x++);), щоб почати з 1
Стріллінг Арчер

32
Просто зміна map(x => x++)до map(x => ++x)приросту пріоритету відбувається після повернення значення :)
Brock

92
Ер що !? Чому 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,

844

Ви можете зробити це:

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,55775759159558545, 0,1577575915958765, 0,1577575915958735, 0,157, 755, 15955, 585, 0,16, 755, 15955, 585, 0,16, 6005, 15955, 585, 0,16, 755, 1595, 585, 0,16, 6005, 1595, 585, 0,16, 755, 555, 585, 575, 596, 585, 585, 585, 585, 585, 585, 575, 585]

Пояснення

По-перше, зауважте, що 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)
неділя

1
Якби це повертає масив, який починається о 1, це фактично відповість на питання ОП
Хай Фан

480

Кілька способів використання 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.from і { 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.
Олексій

4
Остерігайтеся Array.from не підтримується в IE, якщо ви не заповнюєте його полі.
Лорен

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

296

Масиви внутрішньо керують їх довжиною. По мірі їх проходження їх індекси можуть зберігатися в пам'яті та посилатися на них у той момент. Якщо потрібно знати випадковий індекс, 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 Я не сумніваюся, що є корисна скринька, але я гадаю, що вона невелика. Для чого потрібен масив чисел, зазвичай, коли ітерація над масивом, індекс буде використовуватися як частина конструкції циклу - або як аргумент функції певного тіла, або лічильної змінної - тому проведення масиву чисел здається тривіальним просто створити масив заданої ширини або просто змінну, яка містить верхню межу масиву. Я можу придумати кілька випадків використання, але жоден з них не був висловлений ОП
vol7ron

4
Як я вже сказав, мені потрібно заповнити спадне число цифрами від 1 до 10. Це все. Є СЕКС, МОЯ СЕКС. Ось як я знайшов цю сторінку. Тож просто побудувати масив вручну було менш складно, ніж усе, що я бачив тут. Тому мої вимоги не є вимогами ОП. Але я маю свою відповідь.
CigarDoug

1
@ vol7ron Є корисна шафа, у мене теж є. У кутовому, під час підкачки я хочу показати сторінки в нижньому колонтитулі, які можна натискати. Тому я циклірую елементи у поданні з * ngFor = "нехай p pagesCounter". У вас є краще рішення для цього? До речі, перевірити stackoverflow.com/questions/36354325 / ...
Dalibor

186

У 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)
);


3
+1, тому що це цілком великий O краще, ніж бридкий .join.splitваріант - але я все ж думаю, що скромна петля краща.
Робін

Я згоден @Robin - Алгоритмічна складність убік, покірний цикл завжди більш читабельний. Однак з появою лямбдасів на Яві, я думаю map, незабаром стане стандартом для таких речей.
Нейт

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)?
Домінік

11
Для всіх, хто цікавиться, різниця між Array (N) та Array (N) .fill () пояснюється тут
Домінік

108

Використовуйте дуже популярний метод підкреслення _.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) {...} ;. Потім ви можете викликати діапазон (x, y) на будь-якому об’єкті масиву.
Зак Раттнер

8
Скоріше зробіть це метод Arrayзамість того Array.prototype, що немає причин (це навіть може вважатися досить німим) використовувати цей метод у кожному масиві.
adamse

9
Array.range(1, 5)Можливо, було б більш доречно, але в написанні є щось цікаве [].range(1, 5).
MooGoo

"Швидше зробити це методом Array замість Array.prototype" - Яка різниця? Ви маєте на увазі лише конкретний масив?
pilau

3
@pilau Так само, як каже adamse, це виглядає дивно. Якщо це на прототипі, можна сказати 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 немає :(
alex dykyі

суворо, ти знаєш, що таке вихідний код .map? Я не впевнений, чи є це швидше, ніж цикл for, але якщо ні, то теоретично ми можемо просто визначитиProperty і зробити новий
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.

(на основі максимальних цілих значень ), також тут докладніше про набрані масиви ):

(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, але не для швидшої функції?
bluejayke

Точно правильно. Цей простий один вкладиш кожен шукає!
supersan

@supersan, хоча його супер повільно :)
bluejayke

Сучасний javascript з новим fillметодом:Array(255).fill(0,0,255)
cacoder

@cacoder, наскільки це швидко, скільки масивів він створює і скільки ітерацій?
bluejayke

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
David G

Чомусь це рішення не працює у виробничій версії від 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
лол JSPerf ... будь ласка Matt просто beacuse вам не подобається моя відповідь зупинки downvoting мої інші ... stackoverflow.com/a/18344296/2450730 ... використання console.time () або як це називається ... НЕ JSPerf .
кокко

4
FYI: Оскільки Джон Рейсіг вперше опублікував декілька років тому - на деяких платформах (мається на увазі 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 - хоча це не завжди швидше, ніж інші петлі. У деяких браузерах декрементація циклу набагато повільніше, ніж цикл для циклу, ви не можете робити загальні твердження про ефективність JavaScript, тому що існує так багато реалізацій з такою кількістю різних оптимізацій. Однак загалом мені подобається ваш підхід. ;-)
RobG

32

новий спосіб заповнення Array:

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

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


Це справді гарна відповідь, хоча технічно питання було від 1-N, а не 0- (N-1)
bluejayke

31

Якщо ви використовуєте 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);
// ➜ []

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

26

Підсумковий підсумковий звіт .. Drrruummm Rolll -

Це найкоротший код для створення масиву розміром N (тут 10) без використання ES6 . Версія Кокко вище є близькою, але не найкоротшою.

(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 ()]
Грег

Веб-штурм пропонує (новий масив (10)). Ключі (), правильно?
Хлопець

(новий масив (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


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/…
Джош з Карібу

Я зважую це проти синтаксису діапазону підкреслення, і діапазон читається краще.
ooolala

Технічно це не те, Array.fromщо перетворює рідкісні значення в невизначені. Швидше Array(5)називається аргументом об'єкта, який, у свою чергу, інтерпретує розріджені значення як невизначені значення :)
CervEd



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, ти можеш дуже легко створити масив 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})()]

10

Ви можете використовувати заповнення масиву та карту від 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 : "Він не викликається відсутніми елементами масиву (тобто індексами, які ніколи не були встановлені, які мають було видалено або яким ніколи не було призначено значення). "
battlemanz

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]зробити масив ітерабельним. Примітка: null частіше, ніж перший аргумент застосунку, але 0 - коротший.
  • Object.keys(Array.apply(0,Array(3))) // ['0', '1', '2'] потім дістаньте ключі масиву (працює, тому що масиви - це тип. масив - це об'єкт з індексами для ключів.
  • Object.keys(Array.apply(0,Array(3))).map(Number) // [0, 1, 2] і карта над клавішами, перетворюючи рядки в числа.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.