38

Whats the easiest way (with "native" javascript) to duplicate every element in a javascript array?

The order matters.

For example:

a = [2, 3, 1, 4]
// do something with a
a
// a is now [2, 2, 3, 3, 1, 1, 4, 4]
Jan Rüegg
  • 9,587
  • 8
  • 63
  • 105
  • Not preferred/recommended/reliable but regex can also be used. `a = a.join(',').replace(/(\d+)/g, "$1,$1").split(',').map(Number);` – Tushar Oct 24 '15 at 05:06
  • @Tushar Nice idea. However, as you already assumed, I'm looking for a generic solution that also works with arrays of strings that might even contain commas... – Jan Rüegg Oct 26 '15 at 07:25
  • 3
    **The top answers to this question seem to be games of complexity code golf**. Don't use reduce, the intent is super unclear. Sometimes a for loop is the correct answer guys, sorry. – Nathan Cooper Sep 21 '16 at 21:37

12 Answers12

41

I came up with something similar to tymeJV's answer

[2, 3, 1, 4].reduce(function (res, current, index, array) {
    return res.concat([current, current]);
}, []);
Community
  • 1
  • 1
axelduch
  • 10,769
  • 2
  • 31
  • 50
  • I don't understand why the two last parameters (`index`, `array`) are needed if I don't see them used. Can someone please explain this? – MarksCode Jun 29 '17 at 18:21
  • How to duplicate it 10 times? – Zhong Ri Jun 12 '20 at 06:50
  • 3
    `[2,3,1,4].reduce((a,i)=>a.concat(i,i),[])` is a lot easier to read or `a.concat(Array(10).fill(i))`, or map if i is an an object and you need clones – user120242 Jun 24 '20 at 03:09
30

Basically you can use flatMap in ES19

a = [1, 2, 3, 4];
a.flatMap(i => [i,i]); // [1, 1, 2, 2, 3, 3, 4, 4]

Also you can customize the repetitions number like this:

a = [1, 2, 3, 4];
const dublicateItems = (arr, numberOfRepetitions) => 
    arr.flatMap(i => Array.from({ length: numberOfRepetitions }).fill(i));

dublicateItems(a, 3);

My reply to the comment below by @user120242 why so complicated? a.flatMap(i => Array(n).fill(i)) find it here

Zeyad Etman
  • 2,250
  • 5
  • 25
  • 42
17

Basically:

a = [2, 3, 1, 4];
b=[];

for(var i = 0; i< a.length;++i){
  b.push(a[i]);
  b.push(a[i]);
}

a=b;
Jan Rüegg
  • 9,587
  • 8
  • 63
  • 105
morels
  • 2,095
  • 17
  • 24
  • 2
    If anyone wonders which is the best way, I made a benchmark and **this is the fastest** way to duplicate, but if you want to duplicate more than 6 times use nested loops for even more efficient duplication. (Tested on a random array with 100000 elements) – Noel Nemeth Sep 18 '20 at 10:49
  • one can make it even faster if avoid to call to a.length in every step – Sergei Kovalenko Sep 12 '21 at 10:36
  • @SergeiKovalenko do you have any benchmark on that? Because as far as I know `a.length` has O(1) complexity because array length should be implemented as a constant in JS. See https://stackoverflow.com/questions/32850662/time-complexity-of-javascripts-array-length for further info – morels Sep 13 '21 at 15:14
  • @morels, the benchmarks script in the page you provided shows sometimes .length 11 and var 11, but mostly .length 12 and var 10, which is the difference between the calculation and direct access to the value. but there is never .length < var – Sergei Kovalenko Sep 13 '21 at 15:29
  • Do you have any public source? I'm genuinely interested. I cannot replicate your results because I don't know where data comes from, sorry. – morels Sep 14 '21 at 16:16
6

I came across this issue in my application, so I created this function:

function duplicateElements(array, times) {
  return array.reduce((res, current) => {
      return res.concat(Array(times).fill(current));
  }, []);
}

To use it, simple pass the array, and the number of times you want the elements to be duplicated:

duplicateElements([2, 3, 1, 4], 2);
// returns: [2, 2, 3, 3, 1, 1, 4, 4]
Bamieh
  • 10,358
  • 4
  • 31
  • 52
5

I suppose you could do:

var duplicated = a.map(function(item) {
    return [item, item];
}).reduce(function(a, b) { return a.concat(b) });

//duplicated: [2, 2, 3, 3, 1, 1, 4, 4]
Jan Rüegg
  • 9,587
  • 8
  • 63
  • 105
tymeJV
  • 103,943
  • 14
  • 161
  • 157
2

ES6 way of life (based on axelduch's answer)

const arr = [2, 3, 1, 4].reduce((res, current) => [...res, current, current], []);

console.log(arr);
radzak
  • 2,986
  • 1
  • 18
  • 27
2

A very basic snippet by just using loops and push.

It's dynamic function, So you can specify duplicator to duplicate value number of times.

Function name duplicate

Syntax: duplicate (array, duplicator)

  • Array array to be passed in the function.
  • duplicator integer value to be passed to duplicate number of times.

How it works: function takes two parameter array and duplicator, It build new array based on duplicator and return newly built array.

Snippet

function duplicate(array, duplicator){
        var buildArray = [];
        for(i=0; i<array.length; i++){
                for(j=0; j<duplicator; j++){
                        buildArray.push(array[i]);
                }
        }
        return buildArray;
}

Usage

var a = [2, 3, 1, 4];
var result = duplicate(a, 2);
console.log(result);

Change duplicator value according to your requirement to get desired output.

Reference:

push()

Shahnawaz Kadari
  • 1,423
  • 1
  • 12
  • 20
1

Just splice a little bit.

var a = [2, 3, 1, 4],
    i = a.length;
while (i--) {
    a.splice(i, 0, a[i]);
}
document.write('<pre>' + JSON.stringify(a, 0, 4) + '</pre>');
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

These functions may help see .sort(), .concat()

function duplicate(arr) {
    return arr.concat(arr).sort()
} 
console.log(duplicate([1,2,3,4,5]))
tallgirltaadaa
  • 1,804
  • 18
  • 26
1

how 'bout that?

for (i=a.length-1;i>=0;i--)a.splice(i,0,a[i]);

iterating backwards is undervalued, in this case it keeps the index intact ;)

fix-me
  • 21
  • 3
-1
0/2  =  0    =  0  |0  =  0
1/2  =  0.5  =  0.5|0  =  0
2/2  =  1    =  1  |0  =  1
3/2  =  1.5  =  1.5|0  =  1
4/2  =  2    =  2  |0  =  2
5/2  =  2.5  =  2.5|0  =  2
6/2  =  3    =  3  |0  =  3
7/2  =  3.5  =  3.5|0  =  3

Treat |0 as Math.floor


In code this could look like this:

for (let i = 0; i < a.length * 2; i++) {
  a[i] = a[i / 2 | 0]
}

Because immutability is preferable, one could do something like this:

function repeatItems(a, n) {
  const b = new Array(a.length * n)
  for (let i = 0; i < b.length; i++) {
    b[i] = a[i / n | 0]
  }
  return b
}

Unreadable ES6 spaghetti code:

const repeatItems = (a, n) => Array.from(Array(a.length * n), (_, i) => a[i / n | 0])
yckart
  • 32,460
  • 9
  • 122
  • 129
-2

Lot of ways to add items to an array as seen above. I have compared it and you can view the performance by yourself in the console. Whatever is timed goes between the two "console.time"

console.clear();

function loopMyArray(){
 var loopArray = new Array(10000);
 for(var i = 0; i < loopArray.length; i++){
   loopArray[i] = i+1;
 }
 console.log(loopArray);
}
console.time('loopMyArray');
loopMyArray();
console.timeEnd('loopMyArray');

function fillArray(){
 let x = 0;
 let filledArray = new Array(10000).fill(null).map(()=> ++x);
 console.log(filledArray);
}

console.time('fillArray');
fillArray();
console.timeEnd('fillArray');

function keyMyArray(){
 let fromKeyArray = Array.from(Array(10000).keys());
 console.log(fromKeyArray);
}
console.time('keyMyArray');
keyMyArray();
console.timeEnd('keyMyArray');

function spreadKeysArray(){
 let spreadArray = [...Array(10000).keys()];
 console.log(spreadArray);
}
console.time('spreadKeysArray');
spreadKeysArray();
console.timeEnd('spreadKeysArray');

console.log(' Start from 1');

function mapKeyArray(){
 //let mapArray = ([...Array(1000).keys()].map(x => x++)); //increment after return
 let mapArray = [...Array(10000).keys()].map(x => ++x);
 console.log(mapArray);
}

console.time('mapKeyArray');
mapKeyArray();
console.timeEnd('mapKeyArray');

function sliceKeyArray(){
 let sliceFirstElementArray = [...Array(10000+1).keys()].slice(1);
 console.log(sliceFirstElementArray);
}
console.time('sliceKeyArray');
sliceKeyArray();
console.timeEnd('sliceKeyArray');

function calcFromLength(){
 let fromLengthArray = Array.from({length: 10000}, (v, k) => k+1);
 console.log(fromLengthArray);
}
console.time('calcFromLength');
calcFromLength();
console.timeEnd('calcFromLength');

console.log('======== add a double for every item ========');

function loopDoubleArray(){
 var first5000Array = [...Array(5000+1).keys()].slice(1);
 var double5000Array =[];

 for(var i = 0; i< first500Array.length;++i){
   double5000Array.push(first5000Array[i]);
   double5000Array.push(first5000Array[i]);
 }
 console.log(double5000Array);
}
console.time('loopDoubleArray');
loopDoubleArray(); // Whatever is timed goes between the two "console.time"
console.timeEnd('loopDoubleArray');

function mapDoubleArray(){
 // adding 1,1,2,2,3,3 etc
 let doubleArray = [...Array(10000).keys()].map(x => Math.floor(++x/2) + x%2);
 console.log(doubleArray);
}
console.time('mapDoubleArray');
mapDoubleArray();
console.timeEnd('mapDoubleArray');

function fromDoubleArray(){
 let fromDoubleArray = Array.from({length: 10000}, (v, x) => Math.floor(++x/2) + x%2);
 console.log(fromDoubleArray);
}
console.time('fromDoubleArray');
fromDoubleArray(); // Whatever is timed goes between the two "console.time"
console.timeEnd('fromDoubleArray');

function doubleSpreadArray(){
 let keyArray = [...Array(500+1).keys()].slice(1);
 let doubleSpreadArray = [...keyArray,...keyArray];
 console.log(doubleSpreadArray);
}
console.time('doubleSpreadArray');
doubleSpreadArray(); // Whatever is timed goes between the two "console.time"
console.timeEnd('doubleSpreadArray');

function reduceDoubleArray(){
 let reduceDoubleArray = Array.from({length: 5000}, (v, k) => k+1).reduce((m,i) => m.concat([i,i]), []);
 console.log(reduceDoubleArray);
}
console.time('reduceDoubleArray');
reduceDoubleArray(); // Whatever is timed goes between the two "console.time"
console.timeEnd('reduceDoubleArray');

I compared some speeds and it looks as if there are not so many differences. The speed(in ms for 10000 items) of calculation between map, slice and from are not so different (slice one seems a bit better). Using reduce in the calculation for double items array is way more slower then the rest of methods

| mapMyArray     | 5,342041016 | 5,21484375  | 8,424804688 | 5,516113281 |
| sliceKeyArray  | 5,221191406 | 4,854248047 | 6,069091797 | 4,940185547 |
| calcFromLength | 6,156005859 | 5,988037109 | 6,031982422 | 6,739990234 |
Ron Jonk
  • 706
  • 6
  • 16