hatched
hatched

Reputation: 865

javascript - create multidimensional array with elements in array

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)

Upvotes: 1

Views: 111

Answers (3)

Nina Scholz
Nina Scholz

Reputation: 386883

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

Upvotes: 2

CodeManX
CodeManX

Reputation: 11915

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.

Upvotes: 2

StepUp
StepUp

Reputation: 38209

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

Upvotes: 0

Related Questions