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


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/…
Larry Battle

Відповіді:


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

1
@noobninja: чудове рішення; ви повинні повторно ввести його як відповідь, щоб він міг бути застосований
jsalvata

692

В ES6, використовуючи метод Array fill ()

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

3
Internet Explorer і Opera ще не підтримують його.
Денис Колодін

4
Node.js <= 3 це не підтримує.
Junle Li

1
@DenisKolodin Поточна опера робить. І Край теж. Дивіться таблицю з
компат

4
@Michael Ви можете це зробити Array(5).fill([1,2,3]).flat(). Зауважте, що flat () все ще дуже експериментальний, а підтримка веб-переглядача погана.
Ніко Руотсалайнен

3
Зауважте, що аргумент для 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) не працює?
blazkovicz

1
blazkovicz, дивіться коментар zertosh до цієї відповіді з причини.
Росс Роджерс

5
За допомогою ES6 це можна "модернізувати" до Array(...Array(10)).map(() => 5)оператора розповсюдження або також доArray.from(Array(10)).map(() => 5)
Крістоф Відал

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

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

91

Ви можете спробувати:

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

Оновлення (01.01.2018) :

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

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

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

Оновлення (11.11.2019) :

Інший спосіб, не використовуючи fillабо from, який працює для рядка будь-якої довжини:

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

Те саме, що відповідь вище . Додавання заради повноти.


1
Приємно. Найкоротший і простіший.
Йоганн Ечаваррія

2
+1 для простоти обробки. Прикро, що ви не можете створити з цього масив порожніх рядків. Окрім цього дуже розумного ...
Швидше

1
Масив (6) .join ('a'). Split ('a') дає мені масив порожнього рядка.
Vivek

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)=> iє, undefinedоскільки воно представляє порожнє значення Array.from({length:5}, (e, i)=>i)=> eє, undefinedоскільки воно представляє порожнє значення. Це повинно бути Array.from({length:5}, v => 1)іArray.from({length:5}, (v, i)=>i)
Рафаль

33

У лодаші це не так вже й погано:

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

EDIT : Ще краще:

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

EDIT : Ще краще:

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

3
_.times (довжина, _.константа (значення))
користувач1533401

1
з документів: _.fill (масив (3), 2); Що недалеко від ES6
kert

15

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

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

так для [2] * 5

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

Насправді, чи не було б простішим масив (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 не знають про необхідність не прототипу нативних функцій.
brooНо

2
У ES6 додано метод заповнення . Тому я б не рекомендував додавати власні речі до прототипу, ви перезаписуєте більш швидку та більш спроможну версію.
Janus Troelsen

1
@JanusTroelsen Щоб уникнути перезапису JavaScript або сторонніх бібліотек, ви можете перевірити, чи існує, перш ніж оголосити його. if (!Array.prototype.fill) { }
Олівер

1
@JanusTroelsen Що ви маєте на увазі під "справжньою поліфіл" ?. Я використовував поліфілл. Я маю на увазі: перевірити на виявлення та реалізацію функцій, якщо їх немає.
Олівер



4

Немає легшого шляху. Потрібно зробити цикл і просунути елементи в масив.


Дякую! Перш ніж прийняти, pushкраще чи concatкраще, з точки зору ефективності?
Curious2learn

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

Немає потреби в петлях, дивіться мою відповідь.
Янус Троельсен

@JanusTroelsen, немає необхідності в циклі, якщо ви не хочете ефективного способу зробити цю дію. Ваше - одне з повільніших імплементацій, яке ви можете знайти. push () до [] - найшвидший.
chrilith

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 з використанням наявного масиву, що мені було потрібно.
гнерік


1

Ця функція створює масив (довжина) елементів, де кожен елемент дорівнює (значення) до тих пір, як (значення) - ціле число або рядок цілого числа. Будь-які десяткові числа будуть усічені. Якщо ви хочете десяткових чисел, замініть "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

Я виявив це сьогодні, намагаючись зробити 2D масив без використання циклів. Зрештою, приєднання до нового масиву є акуратним; Я спробував зіставити новий масив, який не працює, оскільки карта пропускає порожні слоти.

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

Знаком "#" може бути будь-який дійсний єдиний символ. 5 буде змінною для кількості потрібних елементів. 7 буде значенням, яким ви хочете заповнити свій масив.

Новий метод заповнення є кращим, і коли я кодував це, я не знав, що він існує, і я не знаю, що це повторення - це es6; Я збираюся написати допис у блозі про використання цього трюку в тандемі зі скороченням робити цікаві речі.

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




0

Якщо ви користуєтеся поясом, наприклад лодаш / підкреслення, ви можете зробити це так :)

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


-1

Мені знадобився спосіб повторити / циклічити масив (з n елементів) м разів.

Наприклад, розповсюдження списку (осіб) на тиждень / місяць. Скажімо, у мене є 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.