Dicky Chan
Dicky Chan

Reputation: 245

How to add item in every N items of array in Javascript

In the initial stage, i have an object array:

[
 { type: 'all' },
 { type: 'all' },
 { type: 'all' },
 { type: 'fruit'},
 { type: 'all' },
 { type: 'all' },
 { type: 'fruit' },
 { type: 'all' },
 { type: 'all' },
 { type: 'fruit' },
 { type: 'fruit' }
]

I want to insert :

1) object: {type: 'toys'} in every 5 items with type: all

2) object: {type: 'clothes'} in every 2 items with type: 'fruit'

Expected Result:

[
 { type: 'all' },
 { type: 'all' },
 { type: 'all' },
 { type: 'fruit'},
 { type: 'all' },
 { type: 'all' },
 { type: 'toys' },
 { type: 'fruit' },
 { type: 'clothes' },
 { type: 'all' },
 { type: 'all' },
 { type: 'fruit' },
 { type: 'fruit' },
 { type: 'clothes' }
]

How can i implement this function ? I tried to forEach to add the items, but after pushing an item, the array_demo length is changed and hard to measure which is the next original item of the list.

array_demo.forEach((item, index) => {
  array_demo.push({type: 'demo'});
  console.warn(index);
});

Upvotes: 2

Views: 2924

Answers (7)

cdoublev
cdoublev

Reputation: 784

Got a similar need solved with:

const concatAt = (array, predicate, value) => array.reduce(
    (c, n, idx) => {
        const at = typeof predicate === 'function' ? predicate(idx, n, array) : predicate === idx
        const newValue = typeof value === 'function' ? value(n, idx, array) : value
        return at ? [...c, n, newValue] : [...c, n]
    } , [])
const idOddIndex = n => n % 2
const isNth = nth => n => n % nth === nth - 1
const increment = n => n + 1

console.log(concatAt([0, 1, 3, 4, 6], idOddIndex, increment)) // [0, 1, 2, 3, 4, 5, 6]
concatAt([0, 1, 3, 4, 6], isNth(3), increment) // [0, 1, 3, 4, 4, 6]

I hope it will help someone.

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386746

You could count the occurence and insert if found the right number of apperance and add a new object into the array.

For counting and keeping the logic, this appoach uses an object with the wanted types as keys and all other values, like size and type for inserting.

{
    all: {
        count: 0,
        size: 5,
        type: 'toys'
    },
    fruit: {
        count: 0,
        size: 2,
        type: 'clothes'
    }
}

var array = [{ type: 'all' }, { type: 'all' }, { type: 'all' }, { type: 'fruit'}, { type: 'all' }, { type: 'all' }, { type: 'fruit' }, { type: 'all' }, { type: 'all' }, { type: 'fruit' }, { type: 'fruit' }],
    types = { all: { count: 0, size: 5, type: 'toys' }, fruit: { count: 0, size: 2, type: 'clothes' } },
    type,
    i = 0;

while (i < array.length) {
    type = types[array[i].type];
    if (type && ++type.count === type.size) {
        array.splice(++i, 0, { type: type.type });
        type.count = 0;
    }               
    ++i;
}

console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

Ori Drori
Ori Drori

Reputation: 192507

You can Array#map the data, and use 2 outer counters (fruit, and all) to count the number of occurrences of each one. For each object that has one of the types, increment the counter, and check if it's the 2nd fruit / 5th all. If it matches the criteria return a new array with the original and the added object. Afterwards flatten all sub arrays by spreading in Array#concat.

Note: The solution uses @NinaScholz types object to make it more generic.

const data = [{"type":"all"},{"type":"all"},{"type":"all"},{"type":"fruit"},{"type":"all"},{"type":"all"},{"type":"fruit"},{"type":"all"},{"type":"all"},{"type":"fruit"},{"type":"fruit"}];

const types = {
    all: { count: 0, size: 5, type: 'toys' },
    fruit: { count: 0, size: 2, type: 'clothes' }
};

const result = [].concat(...data.map((o) => {
  const to = types[o.type];

  return !to || ++to.count % to.size ? o : [o, { type: to.type }];
}));

console.log(result);

Upvotes: 0

Lalit
Lalit

Reputation: 1369

var data = 
[
 { type: 'all' },
 { type: 'all' },
 { type: 'all' },
 { type: 'fruit'},
 { type: 'all' },
 { type: 'all' },
 { type: 'fruit' },
 { type: 'all' },
 { type: 'all' },
 { type: 'fruit' },
 { type: 'fruit' }
];

var result = [];
var allCounter = 0;
var fruitCounter = 0;
data.forEach(function(item,index){
  result.push(item);
  if(item.type == "all"){
    allCounter++;
  }
  if(item.type == "fruit"){
    fruitCounter++;
  }
  if(allCounter == 5){
    result.push({"type":"toys"});
    allCounter = 0;
  }
  if(fruitCounter == 2){
    result.push({"type":"clothes"})
    fruitCounter = 0;
  }
});

console.log(result);

Upvotes: 0

Sylvan LE DEUNFF
Sylvan LE DEUNFF

Reputation: 712

Other solution, same result

function insertion(my_array){
    var i=0,
        j=0,
        n=my_array.length,
        k=0;
    while(k<n){
        if(my_array[k].type=='all'){
            i++;console.log(i);
        }else if(my_array[k].type=='fruit'){
            j++;console.log(j);
        }
        if(i==5){
            k++;
            my_array.splice(k,0,{ type: 'toys' });
            i = 0;
            n++;
        }else if(j==2){
            k++;
            my_array.splice(k,0,{ type: 'clothes' });
            j = 0;
            n++;
        }
        k++;
    }
    return my_array;
}

Upvotes: 0

Andr&#233;s
Andr&#233;s

Reputation: 783

A simple and traditional approach:

let init = [
 { type: 'all' },
 { type: 'all' },
 { type: 'all' },
 { type: 'fruit'},
 { type: 'all' },
 { type: 'all' },
 { type: 'fruit' },
 { type: 'all' },
 { type: 'all' },
 { type: 'fruit' },
 { type: 'fruit' }
]

let last = [];
let allCounter = 0;
let fruitCounter = 0;

for (let type of init) {
	last.push(type);

	if (type.type == 'all' ) {
		allCounter++;
		if (allCounter == 5) {
			last.push({type:'toys'})
			allCounter = 0;
		}
	} else if (type.type == 'fruit') {
		fruitCounter++;
		if (fruitCounter == 2) {
			last.push({type: 'clothes'})
			fruitCounter = 0;
		}
	}
}

console.warn(last)

Upvotes: 0

Shubham Khatri
Shubham Khatri

Reputation: 281922

You can make use of reduce and keep a count of all and fruits

const array_demo = [
 { type: 'all' },
 { type: 'all' },
 { type: 'all' },
 { type: 'fruit'},
 { type: 'all' },
 { type: 'all' },
 { type: 'fruit' },
 { type: 'all' },
 { type: 'all' },
 { type: 'fruit' },
 { type: 'fruit' }
]

let all = 0;
let fruit = 0;
const newArray = array_demo.reduce((acc, item, index) => {
  if(item.type === 'all') {
     if(all === 4) {
       acc.push(item);
       acc.push({type: 'toys'})
       all = 0;
       return acc;
     } else {
       all++;
     }
  }else if(item.type === 'fruit') {
    if(fruit === 1) {
       acc.push(item);
       acc.push({type: 'clothes'})
       fruit = 0;
       return acc;
     } else {
       fruit++;
     }
    
  }
  acc.push(item);
  return acc;
  
}, []);
console.log(newArray);

Upvotes: 0

Related Questions