2

I am trying to perfom operation on array that is described in topic. What i've done already - group by common property + map data of each item to desired format. It was achieved by using reduce + map function inside it. Now i need final part that is going to squash each of grouped items properties into 1. My goal is to make it work properly, ideally by extending restructuring function.

Array to restructure

const arrToRestructure = [
{
    x: "test-x1",
    y: "test-y1",
    data: [
        {id: 1, label: "label-y1-1"},
        {id: 2, label: "label-y1-2"}
    ]
},
{
    x: "test-x2",
    y: "test-y1",
    data: [
        {id: 1, label: "label-y1-3"},
        {id: 2, label: "label-y1-4"}
    ]
},
{
    x: "test-x2",
    y: "test-y2",
    data: [
        {id: 1, label: "label-y2-1"},
        {id: 2, label: "label-y2-2"}
    ]
},
]

restructuring function

const restructureArr = () => {
    const restructuredArr = arrToRestructure.reduce(
        (prevVal, nextVal) => ({
        ...prevVal,
        [nextVal["y"]]: [
            ...(prevVal[nextVal["y"]] || []),
            nextVal.data.map((nextVal) => nextVal.label),
        ]})
        ,[]);

    return restructuredArr;
}

current output

{
    "test-y1": [
        [
            "label-y1-1",
            "label-y1-2"
        ],
        [
            "label-y1-3",
            "label-y1-4"
        ]
    ],
    "test-y2": [
        [
            "label-y2-1",
            "label-y2-2"
        ]
    ]
}

desired output

{
    "test-y1": [
        "label-y1-1",
        "label-y1-2",
        "label-y1-3",
        "label-y1-4",
    ],
    "test-y2": [
        "label-y2-1",
        "label-y2-2"
    ]
}
D.Wasilewski
  • 119
  • 3
  • 3
  • 12

3 Answers3

1

Simply spread the Array#map result each time:

const restructureArr = () => {
  const restructuredArr = arrToRestructure.reduce((prevVal, nextVal) => ({
    ...prevVal,
    [nextVal["y"]]: [
      ...(prevVal[nextVal["y"]] || []),
      ...nextVal.data.map((nextVal) => nextVal.label), // fix
    ]
  }) , []);
  return restructuredArr;
}

Some enhancements:

const restructureArr = (arrToRestructure = []) => 
  arrToRestructure.reduce((acc, { y, data = [] }) => ({
    ...acc,
    [y]: [
      ...(acc[y] || []),
      ...data.map(({ label }) => label),
    ]
  }), []);

const arrToRestructure = [
  { x: "test-x1", y: "test-y1", data: [ {id: 1, label: "label-y1-1"}, {id: 2, label: "label-y1-2"} ] },
  { x: "test-x2", y: "test-y1", data: [ {id: 1, label: "label-y1-3"}, {id: 2, label: "label-y1-4"} ] },
  { x: "test-x2", y: "test-y2", data: [ {id: 1, label: "label-y2-1"}, {id: 2, label: "label-y2-2"} ] }
];
console.log(restructureArr(arrToRestructure));
Majed Badawi
  • 27,616
  • 4
  • 25
  • 48
1

You can group based on y value using array#reduce. Push all the label for same y value using array#forEach.

const arrToRestructure = [ { x: "test-x1", y: "test-y1", data: [ {id: 1, label: "label-y1-1"}, {id: 2, label: "label-y1-2"} ] }, { x: "test-x2", y: "test-y1", data: [ {id: 1, label: "label-y1-3"}, {id: 2, label: "label-y1-4"} ] }, { x: "test-x2", y: "test-y2", data: [ {id: 1, label: "label-y2-1"}, {id: 2, label: "label-y2-2"} ] }, ],
      result = arrToRestructure.reduce((r, {y, data}) => {
        r[y] ??= [];
        data.forEach(({label}) => r[y].push(label));
        return r;
      },{});
console.log(result);
Hassan Imam
  • 21,956
  • 5
  • 41
  • 51
  • Upvoting your answer as it also works. Howerver i will stick with @Majed one. Also, big thanks for reminding me that you can actually destructure values inside reduce - so obvious, but didn't come to my mind :P – D.Wasilewski Jan 30 '22 at 14:57
0

Another solution would be using Object.entries and .flat().

const obj = { "test-y1": [ [ "label-y1-1", "label-y1-2" ], [ "label-y1-3", "label-y1-4" ] ], "test-y2": [ [ "label-y2-1", "label-y2-2" ] ] }

const e = Object.entries(obj).map(el => ({[el[0]]: el[1].flat()}))

let o = Object.fromEntries(e.map(x => [Object.keys(x), Object.values(x)[0]]))

console.log(o);
MWO
  • 2,627
  • 2
  • 10
  • 25