简体   繁体   中英

Case insensitive sorting with ramda sortWith

I'm having trouble sorting a deeply nested array of objects using Ramda sortWith by multiple columns (asceding or descending). Apparently the sorting is case sensitive and leads to values starting with lower case letters being put to the very end of the sorted array.

Firstly I import the necessary ramda functions:

import { sortWith, path, useWith, split, ascend, descend } from 'ramda'

Then I have this array:

const theList = [
  {
    name: 'A',
    purchase: {
      period: {
        start: '2020-01-08T21:00:00Z',
        end: '3070-10-27T21:00:00Z',
      },
    },
  },
  {
    name: 'b',
    purchase: {
      period: {
        start: '2019-09-30T19:00:00Z',
        end: '3070-10-27T21:00:00Z',
      },
    },
  },
  {
    name: 'C',
    purchase: {
      period: {
        start: '2020-01-26T21:00:00Z',
        end: '3070-10-27T21:00:00Z',
      },
    },
  },
]

For sorting I have this array with rules:

const sort = [
  { oder: 'asc', name: 'name' },
  { oder: 'desc', name: 'purchase.period.start' },
]

Finally I try to sort this array with the given ruleset:

const sortFunctions = sort.map(({ order, name }) => (
  (order === 'asc')
    ? ascend(useWith(path, [split('.')])(name))
    : descend(useWith(path, [split('.')])(name))
))

return sortWith(sortFunctions)(theList)

However the result is the following:

[
  {
    "name": "b",
    "purchase": {
      "period": {
        "start": "2019-09-30T19:00:00Z",
        "end": "3070-10-27T21:00:00Z"
      }
    }
  },
  {
    "name": "C",
    "purchase": {
      "period": {
        "start": "2020-01-26T21:00:00Z",
        "end": "3070-10-27T21:00:00Z"
      }
    }
  },
  {
    "name": "A",
    "purchase": {
      "period": {
        "start": "2020-01-08T21:00:00Z",
        "end": "3070-10-27T21:00:00Z"
      }
    }
  }
]

So the problem here is that b is not in the middle as expected, because it is taking case sensitivity into account. Not only that, but the list also appears to be in reverse order from the expected order.

What am I doing wrong here and how could I get this to ignore case sensitivity?

With a slightly altered version of your code (using a pipeline rather than useWith , which I prefer to avoid as best I can), we can add toLower inside the comparator like this:

 const makeSorter = compose ( sortWith, map (({order, name}) => (order == 'desc' ? descend : ascend) ( compose (toLower, path (split ('.', name))) )) ) const sorts = [ { order: 'asc', name: 'name' }, { order: 'desc', name: 'purchase.period.start' }, ] // Switched the order to make the sorting clear const theList = [{name: "C", purchase: {period: {start: "2020-01-26T21: 00: 00Z", end: "3070-10-27T21: 00: 00Z"}}}, {name: "A", purchase: {period: {start: "2020-01-08T21: 00: 00Z", end: "3070-10-27T21: 00: 00Z"}}}, {name: "b", purchase: {period: {start: "2019-09-30T19: 00: 00Z", end: "3070-10-27T21: 00: 00Z"}}}] console .log ( makeSorter (sorts) (theList) )
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script> <script> const {compose, sortWith, map, ascend, descend, toLower, path, split} = R </script>

I also changed the test from asc to desc because I've worked with something similar where asc was the default and the field was optional. ( desc was mandatory when it was needed.)

This just avoids some repetition in the functions we pass to ascend or descend :

    (order == 'desc' ? descend : ascend)

I haven't tested that this actually works for multiple sorts, as these values all disagree on 'name', but it looks like it should work.

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