Amelia W
Amelia W

Reputation: 101

Restructure array of objects then grouping objects

So I have found a solution, but I am still learning and feel like my solution is too long. It does not use all of ES6 and could be better. I would love any feedback and/or suggestions.

The data looks like this:

const formattedWorkbook = 
     [
        {
            "year": 2016,
            "mainHeaderEnglish": "Pearls of Wisdom",
            "categoryCode": 3,
        },
        {
            "year": 2017,
            "mainHeaderEnglish": "VENuS Satellite",
            "categoryCode": 2,
        },
        {
            "year": 2017,
            "mainHeaderEnglish": "Hope for millions",
            "categoryCode": 1,
        },
        {
            "year": 2012,
            "mainHeaderEnglish": "green electricity Pioneer",
            "categoryCode": 2
        }
    ]

The data needs to look like this:

const formattedWorkbook = 
     [
        {
            "year": 2016,
            "value: [
               {"mainHeaderEnglish": "Pearls of Wisdom", "categoryCode": 3,}
             ]
        },
        {
            "year": 2017,
            "value":[
              {"mainHeaderEnglish": "VENuS Satellite", "categoryCode": 2},
              {"mainHeaderEnglish": "Hope for millions", "categoryCode": 1}
            ]
        },
        {
            "year": 2012,
            "value": [
              {"mainHeaderEnglish": "green electricity Pioneer", "categoryCode": 2}
            ]
        }
    ]

This is my solution that works, but I think it could be a lot better:

let transformedWorkbook = formattedWorkbook.map(function (obj) {
    const result = {
        year: obj.year,
        value: []
    }

    for (let year in obj) {
        if (obj.hasOwnProperty(year) && year !== "year") {
            result.value.push({ [year]: obj[year] });
        }
    }

    result.value = [Object.assign({}, ...result.value)]
    return result;
});

const newWorkbook = new Map(transformedWorkbook.map(({ year, value }) => [year, { year, value: [] }]));

for (let { year, value } of transformedWorkbook) {
    newWorkbook.get(year).value.push(...[value].flat())
};

console.log([...newWorkbook.values()]);

Upvotes: 2

Views: 784

Answers (3)

Nina Scholz
Nina Scholz

Reputation: 386654

You could still use the map but take year out of the object and map new object with the grouped result.

In pieces:

  • Array.from takes an iterable, like an Array or a Map, where Symbol.iterator is implemented and a mapping function and returns an array.

  • To get a grouped dataset, you could take Array#reduce which uses an accumulator, like an instance of Map and iterates the given array of objects.

    To get a property from the object and keeping the rest,

    { year, ...o }
    

    you could take a destructuring for year and get the rest if object destructuring. Now you have two parts, the wanted property for grouping and the rest for collecting as value.

    Map#get takes a value from the instance and Map#set stores the value.

    In case of not getting an array as value, you need to use a default value

    m.get(year) || []
    

    with logical OR ||, which returns the first truthy value, like an array, but not undefined.

    This value is spreaded into a new array along with the actual object

    [...m.get(year) || [], o]
    

    as new value for the Map.

  • Finally the mapping function of Array.from

    ([year, value]) => ({ year, value })
    

    takes a destructuring of key and value of the given Map and generates a new object with short hand properties as new result.

const formattedWorkbook = [{ year: 2016, mainHeaderEnglish: "Pearls of Wisdom", categoryCode: 3 }, { year: 2017, mainHeaderEnglish: "VENuS Satellite", categoryCode: 2 }, { year: 2017, mainHeaderEnglish: "Hope for millions", categoryCode: 1 }, { year: 2012, mainHeaderEnglish: "green electricity Pioneer", categoryCode: 2 }],
    result = Array.from(
        formattedWorkbook.reduce((m, { year, ...o }) =>
            m.set(year, [...m.get(year) || [], o]), new Map),
        ([year, value]) => ({ year, value })
    );

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

Upvotes: 4

guyaloni
guyaloni

Reputation: 5872

You can use lodash for that:

_.map(formattedWorkbook, el => {
  return {
    year: el.year,
      value: {
        mainHeaderEnglish: el.mainHeaderEnglish,
        categoryCode: el.categoryCode
      }
  }
});

If you prefer native javascript functions:

formattedWorkbook.map(el => {
  return {
    year: el.year,
      value: {
        mainHeaderEnglish: el.mainHeaderEnglish,
        categoryCode: el.categoryCode
      }
  }
});

Upvotes: 0

mickl
mickl

Reputation: 49945

You can use array.reduce to group your array data based on year:

const formattedWorkbook = 
     [
        {
            "year": 2016,
            "mainHeaderEnglish": "Pearls of Wisdom",
            "categoryCode": 3,
        },
        {
            "year": 2017,
            "mainHeaderEnglish": "VENuS Satellite",
            "categoryCode": 2,
        },
        {
            "year": 2017,
            "mainHeaderEnglish": "Hope for millions",
            "categoryCode": 1,
        },
        {
            "year": 2012,
            "mainHeaderEnglish": "green electricity Pioneer",
            "categoryCode": 2
        }
    ]
    
let result = formattedWorkbook.reduce((acc,cur) => {
    let { year, ...rest } = cur;
    let ex = acc.find(x => x.year === year);
    if(!ex){
       ex = { year, value: [] };
       acc.push(ex);
    }
    ex.value.push(rest);
    return acc;
}, [])

console.log(result);

Upvotes: 2

Related Questions