简体   繁体   中英

How to use ramda to sort by last item in an array object

Here's a list of parents and I want to sort the parents by their 2nd's child's age with ramda:

[
  {
    name: "Alicia",
    age: "43",
    children: [{
        name: "Billy",
        age: "3"
      },
      {
        name: "Mary",
        age: "8"
      },
    ]
  },
  {
    name: "Felicia",
    age: "60",
    children: [{
        name: "Adrian",
        age: "4"
      },
      {
        name: "Joseph",
        age: "5"
      },
    ]
  }
]

How do I do on about it? I tried doing something along the lines of

parents.sort(
                sortBy("-children.age"))
            );

Use R.sortBy and extract the value with a function create with R.pipe . The function gets the children array of the object with R.prop , takes the last child ( R.last ), gets the age with R.propOr (returns 0 if no children), and converts to a Number . You can use R.negate if you want to reverse the order.

 const { sortBy, pipe, prop, last, propOr } = R const fn = sortBy(pipe( prop('children'), last, propOr(0, 'age'), Number, // negate - if you want to reverse the order )) const parents = [{"name":"Alicia","age":"43","children":[{"name":"Billy","age":"3"},{"name":"Mary","age":"8"}]},{"name":"Felicia","age":"60","children":[{"name":"Adrian","age":"4"},{"name":"Joseph","age":"5"}]}] const result = fn(parents) console.log(result) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script> 

In vanilla JavaScript (making some assumptions about the relatively poorly formatted input) using the Array.prototype.sort method:

let parents = [ .... ]; // What you have above
parents = parents.sort((a, b) => {
  return a.children[1].age - b.children[1].age; // Change - to + for ascending / descending
});

Be careful though - what would happen if a parent had fewer than 2 children?

Assuming your JSON above was hand generated, including the syntax errors, then assuming your real data is just fine (an array of parents, with each parent having a children array of objects) then a normal JS sort will work just fine:

const compareC2(parent1, parent2) {
  let c1 = parent1.children;
  let c2 = parent2.children;

  if (!c1 || !c2) {
    // what happens if someone has no children?
  }

  let l1 = c1.length;
  let l2 = c2.length;

  if (l1 === 0 || l2 === 0) {
    // different symptom, but same question as above
  }

  if (l1 !== l2) {
    // what happens when the child counts differ?
  }

  if (l1 !== 2) {
    // what happens when there are fewer, or more than, 2 children?
  }

  // after a WHOLE LOT of assumptions, sort based on
  // the ages of the 2nd child for each parent.
  return c1[1].age - c2[1].age;
}  

let sorted = parents.sort(compareC2);

I would use sortWith with ascend functions. Using sortWith allows you to define a first sort order function, a second sort order function, etc.

 const people = [ { name: "Alicia", age: "43", children: [{ name: "Billy", age: "3" }, { name: "Mary", age: "8" }, ] }, { name: "Felicia", age: "60", children: [{ name: "Adrian", age: "4" }, { name: "Joseph", age: "5" }, ] } ]; const by2ndChildAge = ascend(pathOr(0, ['children', 1, 'age'])); const by1stChildAge = ascend(pathOr(0, ['children', 0, 'age'])); console.log(sortWith([by2ndChildAge, by1stChildAge], people)); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script> <script>const {sortWith, ascend, pathOr} = R;</script> 

The simplest solution is, I think, just to combine sortBy with path :

 const sortBy2ndChildAge = sortBy(path(['children', 1, 'age'])) const people = [{name: "Alicia", age: "43", children: [{name: "Billy", age: "3"}, {name: "Mary", age: "8"}]}, {name: "Felicia", age: "60", children: [{name: "Adrian", age: "4"}, {name: "Joseph", age: "5"}]}] console.log(sortBy2ndChildAge(people)) 
 <script src="https://bundle.run/ramda@0.26.1"></script><script> const {sortBy, path} = ramda </script> 

There are several potential flaws with this, that others have noted. Are parents always guaranteed to have at least two children? Do we really want a lexicographic sort -- ie '11' < '2' -- or do you want to convert these values to numbers?

It would be easy enough to fix both of these problems: sortBy(compose(Number, pathOr(0, ['children', 1, 'age']))) , but that depends upon what you're trying to do. If you're just using this to learn about Ramda, then sortBy and path are both useful functions to know. sortBy is useful when you can convert the items to be sorted to some ordered type -- Strings, numbers, dates, or anything with a numeric valueOf method. You supply that conversion function and a list of values and it will sort by that. path is simply a null-safe read for a list of nested properties in an object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM