3

I have some json in the form of:

data = { 
    "1": {"name": "eve", "type": "sergeant", "age": 22},
    "2": {"name": "bob", "type": "sergeant", "age": 33},
    "3": {"name": "bats", "type": "private", "age": 90},
    "4": {"name": "carol", "type": "captain", "age": 50},
    "5": {"name": "noogle", "type": "sergeant", "age": 34},
    "6": {"name": "good", "type": "sergeant", "age": 47},
    "7": {"name": "alice", "type": "private", "age": 34}
}

How can I groupBy their type, and then within each type, they are sorted by their name in ascending order?

I tried to do it with:

let grouped = _.groupBy(Object.keys(data), function(id) {
    return data[id].type;
});

Which will give me something like:

{
    "sergeant": ["1", "2", "5", "6"],
    "private": ["3", "7"],
    "captain": ["4"]
}

But when I try to sortBy it gives me the same object as above:

_.map(Object.keys(grouped), function(type_name) {
    grouped[type_name] = _.sortedBy(grouped[type_name], function(id) {
        return data[id].name;
    });
});

How can I sort the array after I've grouped the objects together? Is there a way I can cleanly chain groupBy and sortBy together instead of splitting logic like I have above?

1
  • 1
    You can't sort the keys of an object. Commented Jun 27, 2018 at 0:15

1 Answer 1

5

You can use the _.mapValues method to sort each group after you've grouped them up by using _.groupBy. Just take each value and return the sorted version of it in your _.mapValues callback function.

Example:

data = { 
    "1": {"name": "eve", "type": "sergeant", "age": 22},
    "2": {"name": "bob", "type": "sergeant", "age": 33},
    "3": {"name": "bats", "type": "private", "age": 90},
    "4": {"name": "carol", "type": "captain", "age": 50},
    "5": {"name": "noogle", "type": "sergeant", "age": 34},
    "6": {"name": "good", "type": "sergeant", "age": 47},
    "7": {"name": "alice", "type": "private", "age": 34}
}

console.log(_.mapValues(_.groupBy(data, "type"), v => _.sortBy(v, "name")))
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

Or, if you just want grouped and sorted keys, or grouped and sorted key/values, you can use the same approach, although its not quite as easy on the eyes:

data = { 
    "1": {"name": "eve", "type": "sergeant", "age": 22},
    "2": {"name": "bob", "type": "sergeant", "age": 33},
    "3": {"name": "bats", "type": "private", "age": 90},
    "4": {"name": "carol", "type": "captain", "age": 50},
    "5": {"name": "noogle", "type": "sergeant", "age": 34},
    "6": {"name": "good", "type": "sergeant", "age": 47},
    "7": {"name": "alice", "type": "private", "age": 34}
}

// If all you want are grouped and sorted keys:
console.log(_.mapValues(_.groupBy(_.keys(data), k => data[k].type), v => _.sortBy(v, i => data[i].name)))

// Or for grouped and sorted keys and values:
console.log(_.mapValues(_.groupBy(_.keys(data), k => data[k].type), v => _.sortBy(v, i => data[i].name).map(k => ({[k]: data[k]}))))
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

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

2 Comments

Is there a way to preserve their given ids? ie, "captain": [ { "4": { "name": "carol" .... } }];
Sure, see the second snippet. It's not as pretty or short, but it does give you the format you mentioned.

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.