2

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

3 Answers 3

4

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

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

2 Comments

really short and elegant, but very much over my head
You are fantastic, thank you for taking the time to write that out.
2

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

Comments

0

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

1 Comment

This is not the output I asked for, the years need to be grouped and values with the same year should be put in a value array inside the object

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.