JS Arrays — Reorganize 1D Array into 2D Array of N Groups Placing Values Sequentially

Viewed 153

I've tried a few approaches to this but I can't seem to come up with a viable solution...

In short, I want to create a function to transform a 1D array of any length into a new 2D array of a specific length. Each value from the 1D array should be sequentially placed into each child-array up to the specified length, then start back at the first child-array.

Input / Desired Output Below:


function groupArray(arr, numberOfGroups) {
 ...
};

// Input Data
const items = [1, 2, 3, 4, 5, 6, 7];
const size = 3;

console.log(groupArray(items, size));
// Expected Output
// [[1, 4, 7], [2, 5], [3, 6]]

4 Answers

You could take the reminder operator % with index and wanted size of the array for getting the right target array.

const
    groupArray = (array, size) => array.reduce((result, value, index) => {
        const target = index % size;
        if (!result[target]) result[target] = [];
        result[target].push(value);
        return result;
    }, []);

console.log(groupArray([1, 2, 3, 4, 5, 6, 7], 3));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Using nested for

function groupArray(arr, numberOfGroups) {
  var result = []

  for (var i = 0; i < numberOfGroups; i++) {
    var subarr = []

    for (var j = i; j < arr.length; j += numberOfGroups) {
      subarr.push(arr[j])
    }

    result.push(subarr)
  }

  return result
};

// Input Data
const items = [1, 2, 3, 4, 5, 6, 7];
const size = 3;

console.log(groupArray(items, size));

Also something like this would do it, you'd not need to mutate any input

const chunkify = (step, list) => list.reduce(
  ([chunk, rest], item, i) => {
    const pick = i % step === 0;  

    return [
      chunk.concat(pick ? item : []),
      rest.concat(pick ? [] : item),
    ];
  },
  [[], []],
);

const group = (step, list, result = []) => {
  if (!list.length) { return result; }
  
  const [chunk, rest] = chunkify(step, list);
  
  return group(step - 1, rest, [...result, chunk]);
};

const data = [1, 2, 3, 4, 5, 6, 7];
const step = 3;

console.log(
  group(step, data),
);

Have method next, each call will return next index and when limit reaches numberOfGroups reset the index 0. (in this case, it will be like 0, 1, 2, 0, 1, 2....)

With this method, can easily push to corresponding output sub array.

const groupArray = (arr, numberOfGroups) => {
  const output = Array.from({ length: numberOfGroups }, () => []);
  const next = index => index % numberOfGroups;
  arr.forEach((num, i) => output[next(i)].push(num));
  return output;
};

// Input Data
const items = [1, 2, 3, 4, 5, 6, 7];
const size = 3;

console.log(groupArray(items, size));

Related