Milan Mendpara
Milan Mendpara

Reputation: 3131

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?

Upvotes: 2

Views: 939

Answers (6)

mikedavies-dev
mikedavies-dev

Reputation: 3355

This function was influenced by adiga's answer but handles the distribution a little better by calculating the insert index based on a decimal interval instead of Math.ceil.

It also avoids mutating the input arrays by creating a copy of the long array before inserting the short array's data.

If you find any cases that it doesn't cover let me know :)

function mergeAndDistributeArrays(array1, array2) {
  // Find the long/short arrays based on length
  const [long, short] =
    array1.length >= array2.length ? [array1, array2] : [array2, array1];

  // Calculate the interval
  const interval = long.length / (short.length + 1);

  // Copy the long array so we don't mutate the input arrays
  const merged = [...long];

  // Iterate the short array and insert the values into the long array
  short.forEach((value, index) => {
    // Calculate the insert index based on the interval and the current index
    const insertAt = Math.ceil(interval * (index + 1));

    // Insert the value
    merged.splice(insertAt + index, 0, value);
  });

  return merged;
}

console.log(
  mergeAndDistributeArrays(
    [1,2,3],
    ['a','b','c','d','e','f','g','h','i']
  )
);

Upvotes: 2

Lakhan Pawar
Lakhan Pawar

Reputation: 1

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]

Upvotes: 0

iopzhu
iopzhu

Reputation: 159

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));

Upvotes: 0

adiga
adiga

Reputation: 35253

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])

Upvotes: 1

Adrian Brand
Adrian Brand

Reputation: 21638

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));

Upvotes: 2

Charlie
Charlie

Reputation: 23818

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);

Upvotes: 1

Related Questions