27

In JavaScript, how can I repeat an array which contains multiple elements, in a concise manner?

In Ruby, you could do

irb(main):001:0> ["a", "b", "c"] * 3
=> ["a", "b", "c", "a", "b", "c", "a", "b", "c"]

I looked up the lodash library, and didn't find anything that was directly applicable. Feature request: repeat arrays. is a feature request for adding it to lodash, and the best workaround given there is

const arrayToRepeat = [1, 2, 3];
const numberOfRepeats = 3;
const repeatedArray = _.flatten(_.times(numberOfRepeats, _.constant(arrayToRepeat)));

The questions Most efficient way to create a zero filled JavaScript array? and Create an array with same element repeated multiple times focus on repeating just a single element multiple times, whereas I want to repeat an array which has multiple elements.

Using reasonably well-maintained libraries is acceptable.

Andrew Grimm
  • 70,470
  • 47
  • 186
  • 310

8 Answers8

26

No need for any library, you can use Array.from to create an array of arrays you want repeated, and then flatten using [].concat and spread:

const makeRepeated = (arr, repeats) =>
  [].concat(...Array.from({ length: repeats }, () => arr));
  
console.log(makeRepeated([1, 2, 3], 2));

On newer browsers, you can use Array.prototype.flat instead of [].concat(...:

const makeRepeated = (arr, repeats) =>
  Array.from({ length: repeats }, () => arr).flat();
  
console.log(makeRepeated([1, 2, 3], 2));
CertainPerformance
  • 260,466
  • 31
  • 181
  • 209
15

You can use the Array constructor along with its fill method to fill it a number of times of the array you want to repeat, then concat them (the subarrays) into a single array:

const repeatedArray = [].concat(...Array(num).fill(arr));

Note: On older browsers (pre-ES6), you can use Function#apply to mimic the rest syntax above (concat will be called with each of the sub arrays passed to it as argument):

var repeatedArray = [].concat.apply([], Array(num).fill(arr));

Example:

const arrayToRepeat = [1, 2, 3];
const numberOfRepeats = 3;

const repeatedArray = [].concat(...Array(numberOfRepeats).fill(arrayToRepeat));

console.log(repeatedArray);
ibrahim mahrir
  • 28,583
  • 5
  • 34
  • 61
12

const repeat = (a, n) => Array(n).fill(a).flat(1)

console.log( repeat([1, 2], 3) )

Recursive alternative:

const repeat = (a, n) => n ? a.concat(repeat(a, --n)) : [];

console.log( repeat([1, 2], 3) )
Slai
  • 19,980
  • 5
  • 38
  • 44
8

My first idea would be creating a function like this

let repeat = (array, numberOfTimes) => Array(numberOfTimes).fill(array).reduce((a, b) => [...a, ...b], [])
console.log(repeat(["a", "b", "c"], 3))

using the fill method and reduce

Ideally, instead of using reduce you could use flatten but there's yet no support in browsers

Gonzalo.-
  • 11,500
  • 5
  • 44
  • 74
1

Unfortunately, it is not possible natively in JS (Also operator overloading is not possible, so we can not use something like Array.prototype.__mul__), but we can create an Array with the proper target length, fill with placeholders, then re-map the values:

const seqFill = (filler, multiplier) => 
  Array(filler.length * multiplier)
  .fill(1)
  .map(
    (_, i) => filler[i % filler.length]
  );

console.log(seqFill([1,2,3], 3));
console.log(seqFill(['a','b','c', 'd'], 5));

Or another way by hooking into the Array prototype, you could use the syntax of Array#seqFill(multiplier), this is probably the closest you can get to ruby syntax (rb can do basically everything with operator overloading, but JS can't):

Object.defineProperty(Array.prototype, 'seqFill', {
  enumerable: false,
  value: function(multiplier) {
    return Array(this.length * multiplier).fill(1).map((_, i) => this[i % this.length]);
  }
});

console.log([1,2,3].seqFill(3));
wiesion
  • 2,118
  • 8
  • 19
1

Apart from the obvious [].concat + Array.from({length: 3}, …)/fill() solution, using generators will lead to elegant code:

function* concat(iterable) {
    for (const x of iterable)
        for (const y of x)
            yield y;
}
function* repeat(n, x) {
    while (n-- > 0)
        yield x;
}

const repeatedArray = Array.from(concat(repeat(3, [1, 2, 3])));

You can also shorten it to

function* concatRepeat(n, x) {
    while (n-- > 0)
        yield* x;
}

const repeatedArray = Array.from(concatRepeat(3, [1, 2, 3]));
Bergi
  • 513,640
  • 108
  • 821
  • 1,164
1

Though other methods works simply, these too.

Array.fill() and Array.from() in previous methods will not work in IE. MDN Docs for Reference

Mehtod 1 : Loop and push (Array.prototype.push) the same into the array.

function mutateArray(arr,n)
{
    var temp = [];
    while(n--) Array.prototype.push.apply(temp,arr);
    return temp;
}
var a = [1,2,3,4,5];
console.log(mutateArray(a,3));

Method 2: Join the array elements and String.repeat() to mutate the string and return the split string.

Note: The repeat method is not supported yet in IE and Android webviews.

function mutateArray(arr,n)
{
    var arr = (arr.join("$")+"$").repeat(n).split("$");
    arr.pop(); //To remove the last empty element
    return arr;
}
var a = [1,2,3,4,5];
console.log(mutateArray(a,3));
Vignesh Raja
  • 5,592
  • 1
  • 25
  • 32
1

Try

Array(3).fill(["a", "b", "c"]).flat()

console.log( Array(3).fill(["a", "b", "c"]).flat() );
Kamil Kiełczewski
  • 53,729
  • 20
  • 259
  • 241