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

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;
};
Curious2learn
источник
4
Возможный дубликат: stackoverflow.com/questions/1295584/…
Ларри
возможный дубликат: stackoverflow.com/questions/1877475/repeat-character-n-times
Benkinass

Ответы:

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;
}
Guffa
источник
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
1
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]

Thomson
источник
Отлично, это лучший подход, если вам нужен динамический элемент
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);
Droogans
источник
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] 

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

Shmiddty
источник
Обратите внимание, что если вы передадите объект в 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" ]
etoxin
источник
отличный oneliner с использованием существующего массива, что мне нужно.
29
2

Еще один вкладыш:

Array.prototype.map.call([]+Array(5+1),function(){ return '2'; })
Филип Херманс
источник
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]
TxRegex
источник
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/

Волшебный Гордон
источник
1

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

"avinash ".repeat(5).trim().split(" ");
Авинаш
источник
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)

Tigregalis
источник
-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"]
akinuri
источник