'Efficiently merge two arrays by distribute values evenly

I have seen many question/answer subject to merge two array by alternating Values. they are working like this:

let array1 = ["a", "b", "c", "d"];
let array2 = [1, 2];

let outcome = ["a",1 ,"b", 2, "c", "d"] 

but i want output to be more efficient with even distribution of value based on array size.

expected outcome = ["a","b", 1, "c", "d", 2] 

other scenario

let array2 = [1];
expected outcome = ["a","b", 1, "c", "d"] 

what should be the best way to achieve this sort of merging?



Solution 1:[1]

Find the ratio of the two arrays' lengths, longest.length/shortest.length and then take that many from the longest for every one in the shortest.

let array1 = ["a", "b", "c", "d", "e"];
let array2 = [1, 2];

const evenDistribute = (array1, array2) => {
  const longest = array1.length > array2.length ? array1 : array2;
  const shortest = array1.length > array2.length ? array2 : array1;
  const ratio = Math.floor(longest.length / shortest.length);
  const results = [];
  for (let i = 0; i < shortest.length; i++) {
    for (let j = 0; j < ratio; j++) {
      results.push(longest[i * ratio + j]);
    }
    results.push(shortest[i]);
  }
  // Grab any that are left over
  for (let i = longest.length - (longest.length % shortest.length); i < longest.length; i++) {
    results.push(longest[i]);
  }
  return results;
}

console.log(evenDistribute(array1, array2));

Solution 2:[2]

The idea is to find out per how many items of the long array you will have to mix an item from the short array. The code below is to demonstrate the concept. Maybe you will have to adjust it a little bit for all edge scenarios.

let array1 = ["a", "b", "c", "d"];
let array2 = [1, 2];


//Get the long and short arrays and calc the length factor
var [longArray, shortArray] = array1.length >= array2.length ? [array1, array2] : [array2, array1];
let lengthFactor = longArray.length / shortArray.length;


var c = 0
let smallIdx = 0;
let result = longArray.flatMap(item => {

  c++;
  
  if (c % lengthFactor === 0) {
    return [item, shortArray[smallIdx++]]
  }
  else
    return [item];    
})


console.log(result);

Solution 3:[3]

You could get the interval for distribution. Then loop through the second array and use splice to update the specific indices of the first array.

function distribute(original, replace) {
  const interval = Math.ceil(original.length / (replace.length + 1));
  replace.forEach((r, i) => original.splice(interval * (i + 1) + i, 0, r))
  console.log(...original)
}

distribute(["a", "b", "c", "d"], [1])
distribute(["a", "b", "c", "d"], [1, 2])
distribute(["a", "b", "c", "d"], [1, 2, 3])
distribute(["a", "b", "c", "d", "e", "f"], [1, 2])
distribute(["a", "b", "c", "d", "e", "f"], [1, 2, 3])

Solution 4:[4]

let array1 = ['a', 'b', 'c', 'd', 'e'];
let array2 = [1, 2];

function merge(arr1, arr2) {
    let newArr1 = JSON.parse(JSON.stringify(arr1));
    let newArr2 = JSON.parse(JSON.stringify(arr2));
    [newArr1, newArr2] = newArr1.length >= newArr2.length ? [newArr1, newArr2] : [newArr2, newArr1];
    const interval = newArr1.length / newArr2.length;
    newArr2.map((item, index) => {
        newArr1.splice(interval * (index + 1), 0, item);
    })
    return newArr1;
}
console.log(merge(array1, array2));

Solution 5:[5]

const mix = (firstArray, secondArray) => {
    const itrArray = firstArray.length > secondArray.length ? firstArray : secondArray;
    const result = [];

    for(let i=0; i<itrArray.length; i++){
        firstArray[i] && result.push(firstArray[i]);
        secondArray[i] && result.push(secondArray[i]);
    }
    return result;
}

console.log(mix([1, 2, 3], [4, 5, 6]));
// [1, 4, 2, 5, 3, 6]
console.log(mix(["h", "a", "c"], [7, 4, 17, 10, 48]));
// ["h", 7, "a", 4, "c", 17, 10, 48]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Charlie
Solution 3 adiga
Solution 4 zhujinwei
Solution 5 Lakhan Pawar