1

I have an array called a and I want to insert an element after every nt-h elements of the array a. For example, I want to put the string XXX after each 3 elements of the array a and as result get a new array b as shown on the next example:

let a = [undefined, "", 0, [], "ee", false, null, {},  Date(), true, (z)=>2*z, Array(0), NaN ];

let b = [undefined, "", 0, "XXX", [], "ee", false, "XXX", null, {}, Date(), "XXX", true, (z)=>2*z, [], "XXX", NaN];

console.log(a, b);

I have tried to do it in this way:

b = [];
a.map((x, i) => b.push((i + 1) % 3 ? x : "XXX"));

https://jsfiddle.net/Lamik/vjfaqn3u/16/

However, there is a problem: The output b array has the same length as input a which is wrong. Any idea or alternative solution?

(UPDATE: in-place solutions are also ok; I cut array a)

Shidersz
  • 16,846
  • 2
  • 23
  • 48
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
  • `a.map` runs over every element of array `a`, meaning it will run exactly as many times as there are elements in the array. What your current code does is replace the value at the 15th spot with `XXX` rather than insert `XXX` – Matthew Herbst Dec 22 '18 at 01:02
  • why not `a.splice(15,0,'XXX');` ? – Muhammad Usman Dec 22 '18 at 01:03

6 Answers6

2

This is one solution that uses a while loop with the Array.splice() method for insert the token every N elements. Also, the logic is wrapped inside a function.

let insertTokenEveryN = (arr, token, n) => {

    // Clone the received array, so we don't mutate the
    // original one. You can ignore this if you don't mind.

    let a = arr.slice(0);
    
    // Insert the <token> every <n> elements.

    let idx = n;

    while (idx <= a.length)
    {
        a.splice(idx, 0, token);
        idx += n + 1;
    }

    return a;
};

let array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
let res1 = insertTokenEveryN(array, "XXX", 2);
let res2 = insertTokenEveryN(array, "XXX", 3);
let res3 = insertTokenEveryN(array, "*", 4);

console.log(JSON.stringify(res1));
console.log(JSON.stringify(res2));
console.log(JSON.stringify(res3));
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
Shidersz
  • 16,846
  • 2
  • 23
  • 48
1

It's probably a better case for reduce() or just a for loop. map() will always give you a new array of the same size. If you're careful with the ending and start you should be able to make it work in the general case with something like.

let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

function insert_after(arr, str, n){
    return arr.reduce((arr, item, i) =>{
        arr.push(item)
        if (i % n == n-1) arr.push(str)
        return arr
    }, [])  
}

console.log(insert_after(arr, 'x', 2).join(','))
console.log(insert_after(arr, 'x', 3).join(','))
Mark
  • 90,562
  • 7
  • 108
  • 148
1

In your example you push instead but not after the element. If you want to use map you can use apply to push either one or two element

a = [1,2,3,4,5,6,7,8,9,10]
b = []
a.map((x,i)=> Array.prototype.push.apply(b, (i+1)%3 ? [x] : [x, "XXX"]))
console.log(b.join(', '))
Hamlet Hakobyan
  • 32,965
  • 6
  • 52
  • 68
  • The use of `map()` is confusing here since. Since you are ignoring the return value, why not use the more appropriate `forEach`? – Mark Dec 22 '18 at 02:25
1

let a= [undefined, "", 0, [], "ee", false, null, {},  Date(), true, (z)=>2*z, Array(0), NaN ];
  
let n = 3+1;
let currentPosition = 3;
let temp ='xxxxxx';

console.log('Before assignment:::',a.length, a);

while(currentPosition <= (a.length+1)){
   a.splice(currentPosition,0,temp);
   currentPosition += n;
}

console.log('new array length:::::',a.length ,a);

I hope this solution will be fine for you. Before inserting the element a length is 13. After 17.

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
Amaranadh Meda
  • 614
  • 4
  • 12
1

As per the given example arrays a and b, you can try the below code to get the expected output.

let a= [undefined, "", 0, Array(0), "eeeeeeeeee", null, "cccccccc", "bbbbbbb", "ddddddddd", Array(0), "bbbbbbb", {}, undefined, "bbbbbbb", {}, null, 0, "ddddddddd", null, "eeeeeeeeee", "ddddddddd", "bbbbbbb", undefined, "cccccccc", "ddddddddd", "ddddddddd", undefined, undefined, "eeeeeeeeee", {}, "", "", undefined, "", "eeeeeeeeee", undefined, Array(0), Array(0), 0, "ddddddddd", "", "", null, null, "bbbbbbb", "", Array(0), null, "ddddddddd", {}];
    let b = [];
    let j = 0, insertIndex = 15;
    let insertVal = "INSERT_VAL";
    for(let i=0; i< a.length;){
        b[j++] = a[i++];
        if(i%insertIndex ==0){
            b[j++] = insertVal;
        }
    }
    console.log(b);
1

Inspired by answers Hamlet Hakobyan and Mark Meyer I provide oneliners for immutable solutions using map and reduce (time complexity O(n))

let b=[]; a.forEach((x,i)=>b.push(x,...(i+1)%k ? [] : ["XXX"]));  

let c = a.reduce((t,x,i)=>t.push(x,...(i+1)%k ? [] : ["XXX"])&&t, []);

and in-place solution (result in a, complexity O(n/k) )

for(let i=a.length/k|0; i; i--) a.splice(i*k,0,"XXX");

I read all of your answer and give +1 because they was interesting, it was hard to choose best but finnaly I choose Amaranadh Meda answer because he first shows that we can reduce time complexity from O(n) to O(n/k) where n is size of array a and k is size of gap between new inserted elements.

let a= [undefined, "", 0, [], "ee", false, null, {},  Date(), true, (z)=>2*z, Array(0), NaN ]; 

let k=3; // gap

// immutable -> result in b
let b=[]; a.forEach((x,i)=>b.push(x,...(i+1)%k ? [] : ["XXX"]));  
let c = a.reduce((t,x,i)=>t.push(x,...(i+1)%k ?[] : ["XXX"])&&t, []);


// in-place -> result in a
for(let i=a.length/k|0; i; i--) a.splice(i*k,0,"XXX"); 

console.log('b=',b);
console.log('c=',c);
console.log('a=',a);
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345