I am looking to sort an array of nested object using Ramda. I have an array:
const people = [
{ name: 'Emma', data:{ age: 70 }},
{ name: 'Peter', data:{ age: 78 }},
{ name: 'Mikhail', data:{ age: 62 }},
];
I want to sort above array using Ramda. I got this but it does not work for me.
Your help will be highly appreciated.
I am looking to sort an array of nested object using Ramda. I have an array:
const people = [
{ name: 'Emma', data:{ age: 70 }},
{ name: 'Peter', data:{ age: 78 }},
{ name: 'Mikhail', data:{ age: 62 }},
];
I want to sort above array using Ramda. I got this but it does not work for me.
Your help will be highly appreciated.
Share Improve this question asked Mar 31, 2020 at 10:58 Saurabh AgrawalSaurabh Agrawal 7,7573 gold badges29 silver badges52 bronze badges 2- 2 have you checked ramdajs./docs ? – Priyanshu Chauhan Commented Mar 31, 2020 at 11:03
- does this help stackoverflow./questions/45820811/… – Code Maniac Commented Mar 31, 2020 at 11:19
2 Answers
Reset to default 4Use R.path to get the data.age
:
const sortByYoungest = R.sortBy(R.path(['data', 'age']))
const people = [{"name":"Emma","data":{"age":70}},{"name":"Peter","data":{"age":78}},{"name":"Mikhail","data":{"age":62}}];
const result = sortByYoungest(people);
console.log(result);
<script src="https://cdnjs.cloudflare./ajax/libs/ramda/0.27.0/ramda.js" integrity="sha256-buL0byPvI/XRDFscnSc/e0q+sLA65O9y+rbF+0O/4FE=" crossorigin="anonymous"></script>
Taking a page from Nick's answer you can create a reusable sortByPath
function using R.pipe:
const sortByPath = R.pipe(R.path, R.sortBy)
const sortByYoungest = sortByPath(['data', 'age'])
const people = [{"name":"Emma","data":{"age":70}},{"name":"Peter","data":{"age":78}},{"name":"Mikhail","data":{"age":62}}];
const result = sortByYoungest(people);
console.log(result);
<script src="https://cdnjs.cloudflare./ajax/libs/ramda/0.27.0/ramda.js" integrity="sha256-buL0byPvI/XRDFscnSc/e0q+sLA65O9y+rbF+0O/4FE=" crossorigin="anonymous"></script>
As you want to sort by the path data.age
, you can get the prop data
from your object using R.prop
which will give you an object, and then use R.prop()
again on that object to get the age
property. To make a function which does this, you can use R.pose()
:
const byAge = R.ascend(R.pose(R.prop('age'), R.prop('data')));
const people = [
{ name: 'Emma', data:{ age: 70 }},
{ name: 'Peter', data:{ age: 78 }},
{ name: 'Mikhail', data:{ age: 62 }},
];
const peopleByYoungestFirst = R.sort(byAge, people);
console.log(peopleByYoungestFirst);
//=> [{"name":"Mikhail","data":{"age":62}},{"name":"Emma","data":{"age":70}},{"name":"Peter","data":{"age":78}}]
<script src="https://cdnjs.cloudflare./ajax/libs/ramda/0.27.0/ramda.js" integrity="sha256-buL0byPvI/XRDFscnSc/e0q+sLA65O9y+rbF+0O/4FE=" crossorigin="anonymous"></script>
To break down the above pose function, say you have the object obj
, which is:
obj = { name: 'Emma', data:{ age: 70 }}
Performing R.prop('data')(obj)
will give:
{ age: 70 }
As you are interested in the age
property of the returned object, you again can run R.prop('age')
on the above object:
R.prop('age')({age: 70})
This will give 70
. So above line can be written as:
R.prop('age')(R.prop('data')(obj))
^^^^^ f ^^^^^ ^^^^^^ g ^^^^^ ^ x
The issue with this function, however, is that it doesn't return a function which we can pass obj
into to get 70
out of. Currently, it takes the form of f(g(x))
, by posing it, we can get the form of (f.g)(x)
, where f.g
poses the functions f
and g
to produce a new function. To pose in Ramda, we can use R.pose()
:
R.pose(R.prop('age'), R.prop('data'))(obj)
This can be eta-reduced to remove the obj
like it is in the example.
This approach can be generalized to:
const {pipe, split, reverse, map, apply, pose, ascend} = R;
const makeSortFn = pose(ascend, pipe(split('.'), reverse, map(R.prop), apply(pose)));
const byAge = makeSortFn('data.age');
const people = [
{ name: 'Emma', data:{ age: 70 }},
{ name: 'Peter', data:{ age: 78 }},
{ name: 'Mikhail', data:{ age: 62 }},
];
const peopleByYoungestFirst = R.sort(byAge, people);
console.log(peopleByYoungestFirst);
//=> [{"name":"Mikhail","data":{"age":62}},{"name":"Emma","data":{"age":70}},{"name":"Peter","data":{"age":78}}]
<script src="https://cdnjs.cloudflare./ajax/libs/ramda/0.27.0/ramda.js" integrity="sha256-buL0byPvI/XRDFscnSc/e0q+sLA65O9y+rbF+0O/4FE=" crossorigin="anonymous"></script>
But instead, I would favour Ori's approach, which can be genralized much easier by splitting a string:
R.sortBy(R.path(path_str.split('.')))