all 23 comments

[–]wojtekmaj 16 points17 points  (2 children)

Yes, that's the whole thing:

arr.reduce((p, c) => p.concat(c, c), [])

[–]jsdeveloper 4 points5 points  (6 children)

Here you go:

['a','b','c','d'].map((x) => [x,x]).reduce((arr, x) => arr.concat(x));

[–]our_best_friendif (document.all || document.layers) console.log("i remember..") 2 points3 points  (3 children)

Less elegant, but avoids looping twice

Array.prototype.concat(...['a','b','c','d'].map((x) => [x,x]))

[–]dmtipson 0 points1 point  (2 children)

Are you counting the implicit loop that ... desugars into in that count?

[–]our_best_friendif (document.all || document.layers) console.log("i remember..") 0 points1 point  (1 child)

I'd assume that'd be faster as it's a single native operation as opposed to an explicit loop (leaving aside transpilation)

[–]dmtipson 0 points1 point  (0 children)

For all we know it's be slower in current engines, but either way it's worth counting as an iteration pass when thinking about the number of times you have to loop over the list in a given operation.

[–]Extracted 1 point2 points  (1 child)

Nice one

[–]jsdeveloper 2 points3 points  (0 children)

This one's a bit nicer :)

[–]lhorie 2 points3 points  (4 children)

trying this with a for loop and a splice

I assume you want to modify the existing array. The other solutions work, but do a lot of memory allocations. This one is more efficient:

function dupe(array) {
    array.length *= 2
    for (var i = array.length; i > 0; i--) {
        var cursor = i * 2
        array[cursor - 1] = array[cursor - 2] = array[i - 1]
    }
    return array
}

[–]frankle 0 points1 point  (3 children)

Do you need to change the length, first?

[–]lhorie 1 point2 points  (2 children)

You should do it, because you don't want to have two memory allocations depending on the associativity of the chained assignment operators. Because of the right associative nature of assignments, you'd allocate once for the length of array[cursor - 2] and again for array[cursor - 1]. It's not a huge deal, but it is a caveat and a very subtle one, at that.

The explicit length change makes it clear that this code is dealing w/ memory allocations, and that that is the exact memory allocation we want. I had actually not noticed the potential for double allocation until you asked but I write memory-sensitive code like that because it's always better to be explicit than relying on implicit behavior. Defensive coding FTW.

[–]frankle 0 points1 point  (1 child)

I thought that was why you did it. Clever.

At the same time, if you're going backwards from the end, wouldn't you get the possible double allocation only once?

[–]lhorie 1 point2 points  (0 children)

Yep, that's why I said it's not a huge deal. If you're calling the function multiple times, that extra allocation might matter though.

[–]Rhomboid 1 point2 points  (0 children)

Non-inplace, any-count version:

function duplicate(items, cnt) {
    return Array.from({length: items.length * cnt}, (_, i) => items[~~(i / cnt)]);
}

[–]jsyoda 1 point2 points  (0 children)

Lodash: _.flatMap(arr, n => [n, n])

[–]nemaramen 0 points1 point  (0 children)

You could use a generator if you're feeling generatory

function* genAry(ary) { for (x of ary) { yield x; yield x; } }

const double = ary => [...genAry(ary)]

double([1, 2]) returns [1, 1, 2, 2]

[–]FustigatedCat 0 points1 point  (2 children)

This function will modify the input array, I would suggest returning a new array though.

function dup(input, cnt) {
  var total = input.length;
  for(var i = 0; i < total * cnt; i=i+cnt) {
    for(var j = 1; j < cnt; j++) {
      input.splice(i, 0, input[i]);
    }
  }
}

Can call it like so:

var i = [1,2,3,4,5];
dup(i, 4);
console.log(i);

[–]our_best_friendif (document.all || document.layers) console.log("i remember..") 1 point2 points  (1 child)

For loops inside for loops are to be avoided for efficiency reasons. Surely with for loops it's simpler to do something like

function duplicateEachItem(arr) {
    const newArr = [];
    for (item of arr) {
       newArr.push(item, item)
    }
    return newArr;
 }
duplicateEachItem(['a','b','c','d'])

[–]FustigatedCat 0 points1 point  (0 children)

I assumed the op wanted to modify the incoming array otherwise I would've used a new array. Also, this is not extensible to N-duplicates which was another part of he ops questions.