0

Here is the list of JavaScript objects that I am working with:

var filtered = [
{'faculty': 'Faculty of Sciences',
 'degree': 'bachelor',
 'majorName': 'Computer Science'},

{'faculty': 'Faculty of Sciences',
 'degree': 'bachelor',
 'majorName': 'Business Computing'},

{'faculty': 'Faculty of Sciences',
 'degree': 'masters',
 'majorName': 'Computer Science'},

{'faculty': 'Faculty of Sciences',
 'degree': 'masters',
 'majorName': 'Business Computing'},

{'faculty': 'School of Arts',
 'degree': 'bachelor',
 'majorName': 'Graphic Design'},

{'faculty': 'School of Arts',
 'degree': 'bachelor',
 'majorName': 'Media and Communication'},

{'faculty': 'School of Arts',
 'degree': 'masters',
 'majorName': 'Musicology'},

{'faculty': 'School of Arts',
 'degree': 'masters',
 'majorName': 'Media'}]

I would like to convert it to a list of nested objects by grouping on faculty and then degree.

Please run this to see what my current result is:

var filtered = [{
    'faculty': 'Faculty of Sciences',
    'degree': 'bachelor',
    'majorName': 'Computer Science'
  },

  {
    'faculty': 'Faculty of Sciences',
    'degree': 'bachelor',
    'majorName': 'Business Computing'
  },

  {
    'faculty': 'Faculty of Sciences',
    'degree': 'masters',
    'majorName': 'Computer Science'
  },

  {
    'faculty': 'Faculty of Sciences',
    'degree': 'masters',
    'majorName': 'Business Computing'
  },

  {
    'faculty': 'School of Arts',
    'degree': 'bachelor',
    'majorName': 'Graphic Design'
  },

  {
    'faculty': 'School of Arts',
    'degree': 'bachelor',
    'majorName': 'Media and Communication'
  },

  {
    'faculty': 'School of Arts',
    'degree': 'masters',
    'majorName': 'Musicology'
  },

  {
    'faculty': 'School of Arts',
    'degree': 'masters',
    'majorName': 'Media'
  }
]


var grouped = _.mapValues(_.groupBy(filtered, 'faculty'),
  flist => flist.map(filtered => _.omit(filtered, 'faculty')));

_.forEach(grouped, function(value, key) {
  grouped[key] = _.groupBy(grouped[key], function(item) {
    return item.degree;
  });
});

console.log(grouped);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>

How can I omit the "degree" property that is left behind? And keep the values of "majorName" property in a list belonging to the generated degree property?

End result could be something like this:

{
"Faculty of Sciences": {
    "bachelor": ["Computer Science", "Business Computing"],
    "masters": ["Computer Science", "Business Computing"]
},
"School of Arts": {
    "bachelor": ["Graphic Design", "Media and Communication"],
    "masters": ["Musicology", "Media"]
}
}

Thank you :)

0

2 Answers 2

3

Using reduce(), destructuring and logical nullish assignment (??=) gives you a concise vanilla solution.

const
  filtered = [{ 'faculty': 'Faculty of Sciences', 'degree': 'bachelor', 'majorName': 'Computer Science' }, { 'faculty': 'Faculty of Sciences', 'degree': 'bachelor', 'majorName': 'Business Computing' }, { 'faculty': 'Faculty of Sciences', 'degree': 'masters', 'majorName': 'Computer Science' }, { 'faculty': 'Faculty of Sciences', 'degree': 'masters', 'majorName': 'Business Computing' }, { 'faculty': 'School of Arts', 'degree': 'bachelor', 'majorName': 'Graphic Design' }, { 'faculty': 'School of Arts', 'degree': 'bachelor', 'majorName': 'Media and Communication' }, { 'faculty': 'School of Arts', 'degree': 'masters', 'majorName': 'Musicology' }, { 'faculty': 'School of Arts', 'degree': 'masters', 'majorName': 'Media' }],
  groupedObjs = filtered.reduce((a, { faculty, degree, ...rest }) =>
    (((a[faculty] ??= { [degree]: [] })[degree] ??= []).push({ ...rest }), a), {}),
  groupedStrings = filtered.reduce((a, { faculty, degree, majorName }) =>
    (((a[faculty] ??= { [degree]: [] })[degree] ??= []).push(majorName), a), {});

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

or without logical nullish assignment...

const
  filtered = [{ 'faculty': 'Faculty of Sciences', 'degree': 'bachelor', 'majorName': 'Computer Science' }, { 'faculty': 'Faculty of Sciences', 'degree': 'bachelor', 'majorName': 'Business Computing' }, { 'faculty': 'Faculty of Sciences', 'degree': 'masters', 'majorName': 'Computer Science' }, { 'faculty': 'Faculty of Sciences', 'degree': 'masters', 'majorName': 'Business Computing' }, { 'faculty': 'School of Arts', 'degree': 'bachelor', 'majorName': 'Graphic Design' }, { 'faculty': 'School of Arts', 'degree': 'bachelor', 'majorName': 'Media and Communication' }, { 'faculty': 'School of Arts', 'degree': 'masters', 'majorName': 'Musicology' }, { 'faculty': 'School of Arts', 'degree': 'masters', 'majorName': 'Media' }],
  groupedObjs = filtered.reduce((a, { faculty, degree, ...rest }) => {
    a[faculty] = a[faculty] || { [degree]: [] };
    (a[faculty][degree] = a[faculty][degree] || []).push({ ...rest });
    return a
  }, {}),
  groupedStrings = filtered.reduce((a, { faculty, degree, majorName }) => {
    a[faculty] = a[faculty] || { [degree]: [] };
    (a[faculty][degree] = a[faculty][degree] || []).push(majorName);
    return a
  }, {});

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

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

5 Comments

Thank you for your answers @pilchard , this is precisely what I was searching for. Another issue is that the output is displayed correctly but the elements (majors) in the array get put out as "undefined" on the console. Any idea to why this is happening?
No worries. How are you attempting to access them when they come out as undefined? For the example grouping arrays of strings you can access specific 'majors' thus groupedStrings['Faculty of Sciences']['bachelor'][0] or for the grouped objects groupedObjs['Faculty of Sciences']['bachelor'][0]['majorName']
I am simply using console.log(groupedStrings) and this is part of the result I get on Chrome's console: "Business Administration: Bachelor: Array(3) 0: undefined 1: undefined 2: undefined length: 3". Same goes to when I try to log groupedStrings['Business Administration']['Bachelor'][0].
Hmm, that's curious, I just ran it in the console and all comes back fine.
It's working just fine now. It was a typo from my end since the real data has different object properties. Thank you :)
2

You can .map each of the arrays again to only select majorName field.

Here is an example

const filtered = [{ 'faculty': 'Faculty of Sciences', 'degree': 'bachelor', 'majorName': 'Computer Science' }, { 'faculty': 'Faculty of Sciences', 'degree': 'bachelor', 'majorName': 'Business Computing' }, { 'faculty': 'Faculty of Sciences', 'degree': 'masters', 'majorName': 'Computer Science' }, { 'faculty': 'Faculty of Sciences', 'degree': 'masters', 'majorName': 'Business Computing' }, { 'faculty': 'School of Arts', 'degree': 'bachelor', 'majorName': 'Graphic Design' }, { 'faculty': 'School of Arts', 'degree': 'bachelor', 'majorName': 'Media and Communication' }, { 'faculty': 'School of Arts', 'degree': 'masters', 'majorName': 'Musicology' }, { 'faculty': 'School of Arts', 'degree': 'masters', 'majorName': 'Media' }];

const grouped = _(filtered).groupBy('faculty')
  .mapValues(l => _(l).map(o => _.omit(o, 'faculty'))
    .groupBy("degree")
    .mapValues(x => _(x).map(y => y.majorName))
  )

console.log(grouped);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>

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.