1

I need to generate a multidimensional array from a multidimensional array.
For example, my array:

var codes = [

['2', '12521', '3'],
['3', '32344', '2'],
['3', '35213', '2'],
['4', '42312', '2'],
['4', '41122', '1'],
['5', '51111', '1']

];

And I need to group the array based on element: For example grouping based on 1st element:

[0] => Array
    (
        [0] => Array
            (
               [0] => '2'
               [1] => '12521'
            }
    )  
[1] => Array
    (
        [0] => Array
            (
               [0] => '3'
               [1] => '32344'
               [2] => '3'
            }
        [1] => Array
            (
               [0] => '3'
               [1] => '35213'
               [2] => '2'
            }
    )  
[2] => Array
    (
        [0] => Array
            (
               [0] => '4'
               [1] => '42312'
               [2] => '2'
            }
        [1] => Array
            (
               [0] => '4'
               [1] => '41122'
               [2] => '1'
            }
    )  
...

var codes = [

    ['2', '12521', '3'],
    ['3', '32344', '2'],
    ['3', '35213', '2'],
    ['4', '42312', '2'],
    ['4', '41122', '1'],
    ['5', '51111', '1']

];
    
const output = codes.reduce(({result, current}, [x, ...y]) => {
  if (current !== x) result.push([]);
  result[result.length - 1].push([x, ...y]);
  
  return {result, current: x};
}, {result: []}).result;

console.log(output);

For the function , i can group based on the 1st element. But what if I need to group based on 2nd , 3rd element, any ways to do it without switching the position of the array elements (for example, not switching 3rd element to the 1st position and run the function)

3 Answers 3

2

You could specify an index and check the previous element for getting a new group.

var codes = [['2', '12521', '3'], ['3', '32344', '2'], ['3', '35213', '2'], ['3', '32344', '2'], ['3', '35213', '2'], ['3', '32344', '2'], ['3', '35213', '2'], ['4', '42312', '2'], ['4', '41122', '1'], ['5', '51111', '1']],
    index = 0,
    output = codes.reduce((result, data, i, array) => {
        if (!array[i - 1] || data[index] !== array[i - 1][index] || result[result.length - 1].length === 5) result.push([]);
        result[result.length - 1].push(data);
        return result;
    }, []);

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

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the solution! working fine , just for an extra condition , if the group of element has more than 5 , then the 6th element will be inserted to the next array , i tried adding || data[index].length == 5 into the if condition but it seems doesnt work
2

Instead of hard-coding it to group by the first element of the inner arrays using destructuring – which is positional – [x, ...y], you can leave the arrays untouched and instead use a parameter to select the index you want to group by.

//edit: this is the same answer as Nina, who replied faster

I recommend to wrap this in a function:

const codes = [
    ['2', '12521', '3'],
    ['3', '32344', '2'],
    ['3', '35213', '2'],
    ['4', '42312', '2'],
    ['3', '32344', '2'],
    ['3', '35213', '2'],
    ['3', '35213', '2'],
    ['4', '41122', '1'],
    ['5', '51111', '1']
];

const group_adjacent = (array, index) =>
  array.reduce(({result, current}, elems) => {
    if (current !== elems[index]) result.push([]);
    result[result.length - 1].push(elems);
    return {result, current: elems[index]};
  }, {result: []}).result;

const output = group_adjacent(codes, 2); // 3rd column
console.log(output);

Note that this is not a general purpose grouping function! It only groups adjacent arrays where the element at index has the same value as the previous sibling.

// if grouped by index 2,
// the 1st and 3rd array won't end up in the same group!
const codes = [
    ['4', '41122', '1'],
    ['4', '42312', '2'],
    ['5', '51111', '1']
];

So make sure that the input has the column you group by sorted if you want a single group per value.

If you want to define a maximum number of arrays per group, you can introduce another parameter and start the next group if the current group has that many elements already. I also added sorting as an exercise (using a copy of the input array):

const codes = [
    ['2', '12521', '3'],
    ['3', '32344', '2'],
    ['3', '35213', '2'],
    ['4', '42312', '2'],
    ['3', '65432', '2'],
    ['3', '65656', '2'],
    ['4', '41122', '1'],
    ['3', '56565', '2'],
    ['3', '55665', '2'],
    ['5', '51111', '1']
];

const group_by = (array, index, max) => {
  max = max || Infinity;
  array = [...array].sort((a, b) => b[index] - a[index]);
  return array.reduce(({result, current}, elems) => {
    if (current !== elems[index] || result[result.length - 1].length >= max) result.push([]);
    result[result.length - 1].push(elems);
    return {result, current: elems[index]};
  }, {result: []}).result;
}

const output = group_by(codes, 2, 5); // up to 5 per group
console.log(output);

Final remark: there are no safe guards against malformed input data. If one of the codes misses the value you group by – like ['2', '12521', /* missing */ ] – then you get some probably undesired output.

2 Comments

Thanks for the solution! working fine , just for an extra condition , if the group of element has more than 5 , then the 6th element will be inserted to the next array , can I know how do I add that condition into the if statement ?
@hatched I added an example to cap the number of arrays per group to a maximum value which you can pass as third argument. So if e.g. the 3rd column has 7 adjacent '2', then you will get a group of 5 and a group of 2.
0

You can group items by reduce method and then just use desired items from grouped:

var codes = [
['2', '12521', '3'],
['3', '32344', '2'],
['3', '35213', '2'],
['4', '42312', '2'],
['4', '41122', '1'],
['5', '51111', '1']
];


let grouped = codes.reduce((a, [el1, el2, el3]) => {
a[el1] = a[el1] || {data: []};
a[el1].data.push([el1, el2, el3]);
return a;
}, {});

grouped = Object.values(grouped);
const result =  grouped.map(s => s.data);
console.log(result);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.