Создать массив с одним и тем же элементом, повторенным несколько раз


323

В Python, где [2]находится список, следующий код дает такой вывод:

[2] * 5 # Outputs: [2,2,2,2,2]

Существует ли простой способ сделать это с помощью массива в JavaScript?

Я написал следующую функцию для этого, но есть что-то короче или лучше?

var repeatelem = function(elem, n){
    // returns an array with element elem repeated n times.
    var arr = [];

    for (var i = 0; i <= n; i++) {
        arr = arr.concat(elem);
    };

    return arr;
};

4
Возможный дубликат: stackoverflow.com/questions/1295584/…
Ларри

Ответы:


52

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

function fillArray(value, len) {
  if (len == 0) return [];
  var a = [value];
  while (a.length * 2 <= len) a = a.concat(a);
  if (a.length < len) a = a.concat(a.slice(0, len - a.length));
  return a;
}

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


Примечание: вы также можете значительно улучшить свою функцию, используя pushвместо concat, так как concatбудет создавать новый массив при каждой итерации. Вот так (показано только в качестве примера того, как вы можете работать с массивами):

function fillArray(value, len) {
  var arr = [];
  for (var i = 0; i < len; i++) {
    arr.push(value);
  }
  return arr;
}

11
Это гораздо более эффективно распределить все записи вперед, с arr = new Array(len);, а затем назначить их по индексу в петле, то есть arr[i] = value;. Таким образом, вы платите только O (n), а не перераспределяете массив по мере его роста. В общем, всегда лучше избегать растущих массивов, добавляя, когда это возможно. Если вы знаете окончательный размер, используйте его.
Том Карзес

26
Array.from({length:5}).map(x => 2)
Нообниня

1
@noobninja: отличное решение; Вы должны повторно ввести его в качестве ответа, чтобы за него проголосовали.
jsalvata

693

В ES6 используется метод Array fill ()

Array(5).fill(2)
//=> [2, 2, 2, 2, 2]

3
Internet Explorer и Opera пока не поддерживают это.
ДенисКолодин

4
Node.js <= 3 не поддерживает это.
Джунл Ли

1
@DenisKolodin Текущая Опера делает. И Эдж тоже. Посмотреть сравнительную таблицу
Янус Троелсен

4
@ Майкл Ты можешь сделать это с Array(5).fill([1,2,3]).flat(). Обратите внимание, что flat () все еще очень экспериментальная, а поддержка браузера слабая.
Нико Руотсалайнен

3
Обратите внимание, что аргумент to fillвычисляется один раз, поэтому в массиве Array(9).fill(someMutable)создается девять ссылок someMutable(мутирует один, мутирует их все).
Карл Смит

146
>>> Array.apply(null, Array(10)).map(function(){return 5})
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
>>> //Or in ES6
>>> [...Array(10)].map((_, i) => 5)
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5]

6
Глупый вопрос, но почему новый Array (10) .map не работает?
Blazkovicz


5
С ES6, это может быть «повышен» , чтобы Array(...Array(10)).map(() => 5)с оператором распространения или такжеArray.from(Array(10)).map(() => 5)
Christophe Vidal

4
Согласно MDN , вы можете просто так:Array.from({length: 10}, () => 5);
Plusb Preco

2
@blazkovicz Array (10) создает массив lenght = 10без перечисляемых свойств. .mapработает только на перечисляемых свойствах. .applyМетод принимает этот массив, и отображает его в arguments array(массив-подобный объект) , который будет передан в Arrayфункцию конструктора. Массив arguments не может быть разреженным, поэтому отсутствующие свойства устанавливаются undefinedи становятся перечисляемыми. Теперь мы можем использовать .mapкак
положено

91

можешь попробовать:

Array(6).join('a').split(''); // returns ['a','a','a','a','a'] (5 times)

Обновление (01/06/2018) :

Теперь вы можете повторять набор символов.

new Array(5).fill('a'); // give the same result as above;
// or
Array.from({ length: 5 }).fill('a')

Примечание: Проверьте больше о заполнении (...) и from (...) для совместимости и поддержки браузера.

Обновление (05/11/2019) :

Другой способ, без использования fillили from, который работает для строки любой длины:

Array.apply(null, Array(3)).map(_ => 'abc') // ['abc', 'abc', 'abc']

То же, что выше ответ . Добавляем ради полноты.


1
Ницца. Самый короткий и простой.
Иоганн Эчаваррия

2
+1 за простую обработку. Жаль, что вы не можете создать массив пустых строк из этого. Помимо этого очень умный ...
Более

1
Array (6) .join ('a'). Split ('a') дает мне массив пустой строки.
Вивек

17
Это работает только для 1 строки символов, поэтому не дает полного ответа на вопрос.
az_

3
@AlfonsoVergara: в Javascript String является примитивным (ценностно-семантическим) типом; нет способа получить две строки для ссылки на одни и те же данные (потому что строки не являются ссылками в Javascript; они являются значениями). Вы должны следить за семантикой ссылок с объектами и списками, но не со строками.
Quuxplusone

36

Array.from({length:5}, i => 1) // [1, 1, 1, 1, 1]

или создать массив с возрастающим значением

Array.from({length:5}, (e, i)=>i) // [0, 1, 2, 3, 4]


Отлично, это лучший подход, если вам нужен динамический элемент
IliasT

Array.from({length:5}, i => 1)=> iis, undefinedпоскольку он представляет пустое значение Array.from({length:5}, (e, i)=>i)=> eis, undefinedпоскольку он представляет пустое значение. Это должно быть Array.from({length:5}, v => 1)иArray.from({length:5}, (v, i)=>i)
Рафал Enden

33

В Лодаше все не так плохо

_.flatten(_.times(5, function () { return [2]; }));
// [2, 2, 2, 2, 2]

РЕДАКТИРОВАТЬ : Еще лучше:

_.times(5, _.constant(2));
// [2, 2, 2, 2, 2]

РЕДАКТИРОВАТЬ : Еще лучше:

_.fill(Array(5), 2);

3
_.times (length, _.constant (value))
user1533401

1
из документов: _.fill (Array (3), 2); Который не далеко от ES6
Керт

15

[c] * n можно записать как:

Array(n+1).join(1).split('').map(function(){return c;})

Таким образом, для [2] * 5

Array(6).join(1).split('').map(function(){return 2;})

На самом деле, не проще ли Array (6) .join (2) .split ('')? Зачем вам нужна карта?
Анжела

4
который возвращает ["2", "2", "2", "2", "2"] вместо [2, 2, 2, 2, 2].
Брук Хонг

10

Вы также можете расширить функциональность Array следующим образом:

Array.prototype.fill = function(val){
    for (var i = 0; i < this.length; i++){
        this[i] = val;
    }
    return this;
};
// used like:
var arry = new Array(5)​.fill(2);
// or
var arry = new Array(5);
arry.fill(2);


console.log(arry);​ //[2, 2, 2, 2, 2] 

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


Обратите внимание, что если вы передадите объект в fillкаждый индекс в массиве, он будет ссылаться на один и тот же объект, поэтому изменение одного из них изменит их все. Это не так сложно решить, если это станет проблемой.
Шмиддты

Я не понимаю, почему многие пользователи javascript не знают о необходимости не создавать прототипы нативных функций.
brooNo

2
Метод заливки был добавлен в ES6. Поэтому я бы не рекомендовал добавлять свои собственные вещи в прототип, вы перезапишете более быструю и более функциональную версию.
Янус Троелсен

1
@JanusTroelsen Чтобы избежать перезаписи javascript или сторонних библиотек, вы можете проверить, существует ли, прежде чем объявить его. if (!Array.prototype.fill) { }
Оливер

1
@JanusTroelsen Что вы подразумеваете под "настоящим полифиллом"? Я использовал полифилл. Я имею в виду: проверить обнаружение и реализацию функции, если это не так.
Оливер


5

Если вам нужно повторить массив несколько раз:

var arrayA = ['a','b','c'];
var repeats = 3;
var arrayB = Array.apply(null, {length: repeats * arrayA.length})
        .map(function(e,i){return arrayA[i % arrayA.length]});
// result: arrayB = ['a','b','c','a','b','c','a','b','c']

вдохновленный этим ответом


в es6 вы можете сделать «abc» .repeat (3)
Янус Троелсен

4

Нет проще. Вам нужно сделать цикл и вставить элементы в массив.


Спасибо! Прежде чем принять, pushлучше или concatлучше, с точки зрения эффективности?
Curious2learn

CONCAT необходимо проверить два массива, PUSH просто добавляет еще один элемент, поэтому я ожидаю, что PUSH в целом будет более эффективным, но для ИДЕНТИЧНЫХ ДАННЫХ я думаю, что ответ Guffa прибивает его.
Диодей - Джеймс Макфарлейн

Нет необходимости в петлях, смотрите мой ответ.
Янус Троелсен

@JanusTroelsen, не нужно зацикливаться, если вы не хотите эффективный способ сделать это действие. Твоя - одна из самых медленных реализаций, которые ты можешь найти. push () to [] - самый быстрый.
Крилит

4

Используйте эту функцию:

function repeatElement(element, count) {
    return Array(count).fill(element)
}
>>> repeatElement('#', 5).join('')
"#####"

Или для более компактной версии:

const repeatElement = (element, count) =>
    Array(count).fill(element)
>>> repeatElement('#', 5).join('')
"#####"

Или для версии с карри:

const repeatElement = element => count =>
    Array(count).fill(element)
>>> repeatElement('#')(5).join('')
"#####"

Вы можете использовать эту функцию со списком:

const repeatElement = (element, count) =>
    Array(count).fill(element)

>>> ['a', 'b', ...repeatElement('c', 5)]
['a', 'b', 'c', 'c', 'c', 'c', 'c']

4

Если вам нужно повторить массив, используйте следующее.

Array.from({ length: 3 }).fill(['a','b','c']).flat()

вернется

Array(9) [ "a", "b", "c", "a", "b", "c", "a", "b", "c" ]

отличный oneliner с использованием существующего массива, что мне нужно.
29


1

Эта функция создает массив элементов (length), где каждый элемент равен (value), если (value) является целым числом или строкой целого числа. Любые десятичные числа будут усечены. Если вам нужны десятичные числа, замените "parseInt ( " на " parseFloat ( ")

function fillArray(length, intValue) {
     var vals = (new Array(length + 1)).join(intValue + '|').split('|').slice(0,length);
     for(var i = 0; i < length; i += 1) {
         vals[i] = parseInt(vals[i]);
     }
     return vals;
}

Примеры:

fillArray(5, 7) // returns [7,7,7,7,7]
fillArray(5, 7.5) // returns [7,7,7,7,7]
fillArray(5, 200) // returns [200,200,200,200,200]

1

У меня были проблемы с упомянутыми методами, когда я использую массив, как

var array = ['foo', 'bar', 'foobar'];
var filled = array.fill(7);

//filled should be ['foo', 'bar', 'foobar', 'foo', 'bar', 'foobar', 'foo']

Чтобы получить это я использую:

Array.prototype.fill = function(val){
    var l = this.length;
    if(l < val){
        for(var i = val-1-l; i >= 0; i--){
            this[i+l] = this[i % l];
        }
    }
    return this;
};

Это хорошо, но, вероятно, должно быть названо cycle.
Дренми

1

Я обнаружил это сегодня, пытаясь создать двумерный массив без использования циклов. Оглядываясь назад, можно сказать, что присоединение к новому массиву очень удобно; Я попытался отобразить новый массив, который не работает, так как карта пропускает пустые слоты.

"#".repeat(5).split('').map(x => 0)

Символ "#" может быть любым допустимым одиночным символом. 5 будет переменной для количества элементов, которые вы хотите. 7 будет значением, которым вы хотите заполнить ваш массив.

Новый метод заполнения лучше, и когда я его кодировал, я не знал, что он существует, и я не знал, что повторитель es6; Я собираюсь написать сообщение в блоге об использовании этого трюка в тандеме с «уменьшить», чтобы делать классные вещи.

http://jburger.us.to/2016/07/14/functionally-create-a-2d-array/




0

Если вы используете пояс utlity, например, lodash / underscore, вы можете сделать это следующим образом :)

let result = _.map(_.times(foo), function() {return bar})

0

Может использоваться как однострочник:

function repeat(arr, len) {
    while (arr.length < len) arr = arr.concat(arr.slice(0, len-arr.length));
    return arr;
}

0

Улучшение ответа Vivek , это работает для строк любой длины, чтобы заполнить массив длины n:Array(n+1).join('[string to be repeated][separator]').split('[separator]').slice(0, n)


-1

Мне нужен был способ повторить / зациклить массив (с n элементов) m раз.

Например, распространение списка (лиц) на неделю / месяц. Допустим, у меня есть 3 имени, и я хочу их повторить через неделю:

fillArray(["Adam", "Blair", "Curtis"], 7); // returns ["Adam", "Blair", "Curtis", "Adam", "Blair", "Curtis", "Adam"]

function fillArray(pattern, count) {
    let result = [];
    if (["number", "string"].includes(typeof pattern)) {
        result = new Array(5);
        result.fill(pattern);
    }
    else if (pattern instanceof Array) {
        for (let i = 0; i < count; i++) {
            result = result.concat(pattern);
        }
        result = result.slice(0, count);
    }
    return result;
}

fillArray("a", 5);        // ["a", "a", "a", "a", "a"]
fillArray(1, 5);          // [1, 1, 1, 1, 1]
fillArray(["a", "b"], 5); // ["a", "b", "a", "b", "a"]
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.