javascript - Get ascendingdescending by a variable with ramda - Stack Overflow

I have a list of users that I want to sort by name. The list would look like this:const data = [{ id: 2

I have a list of users that I want to sort by name. The list would look like this:

const data = [
  { id: 2, name: 'Asterios' },
  { id: 1, name: 'Alex' },
  { id: 4, name: 'Tim' },
  { id: 3, name: 'Sadie' },
]

I have implemented a relatively simple selector which will sort the list of users based on some property.

const getUserList = createSelector(
  getUsers,
  getSortBy,
  getSortOrder,
  (users, sortBy, sortOrder) => R.sortWith([
    R.ascend(R.prop(sortBy)),
  ])(users),
);

However, I want to take the variable sortOrder, which can be either 'ASC' or 'DESC', and apply that sort order.

I tried something like this:

const sortDirection = R.ifElse(R.equals('DESC'), descend, ascend);

sortWith([ pose(sortDirection(sortOrder), prop('name')), ])

Is there a good way to apply this ascending/descending sorting logic via a variable?

I have a list of users that I want to sort by name. The list would look like this:

const data = [
  { id: 2, name: 'Asterios' },
  { id: 1, name: 'Alex' },
  { id: 4, name: 'Tim' },
  { id: 3, name: 'Sadie' },
]

I have implemented a relatively simple selector which will sort the list of users based on some property.

const getUserList = createSelector(
  getUsers,
  getSortBy,
  getSortOrder,
  (users, sortBy, sortOrder) => R.sortWith([
    R.ascend(R.prop(sortBy)),
  ])(users),
);

However, I want to take the variable sortOrder, which can be either 'ASC' or 'DESC', and apply that sort order.

I tried something like this:

const sortDirection = R.ifElse(R.equals('DESC'), descend, ascend);

sortWith([ pose(sortDirection(sortOrder), prop('name')), ])

Is there a good way to apply this ascending/descending sorting logic via a variable?

Share Improve this question asked May 3, 2018 at 18:15 corvidcorvid 11.2k12 gold badges71 silver badges134 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 6

Ok, you have several minor problems here. It's often easier to debug one big problem, though, than several small ones.

Using ifElse properly

The first one is the use of ifElse. This takes three functions as parameters, and returns a new function which, depending on the result of calling the first one with your arguments, calls either the second or third function with those arguments. Note that it doesn't return the function; it calls it. There are several ways to fix this. You could wrap those functions with always:

const sortDirection = R.ifElse(R.equals('DESC'), always(descend), always(ascend))

But I think it's simpler to forgo point-free and use

const sortDirection = dir => (dir === 'DESC' ? descend : ascend)

Understanding pose

Second, you're passing a slightly wrong value into ascend or descend. Although this isn't quite the implementation, think of ascend as something like

const ascend = curry(fn, a, b) => fn(a) < fn(b) ? -1 : fn(a) > fn(b) ? 1 : 0);

Note that if you pass a unary function to this, such as fn = prop('name'), you get back (a, b) => fn(a) < fn(b) ? -1 : fn(a) > fn(b) ? 1 : 0, which is a binary parator function. sortWith accepts a list of parators. So this would be fine.

But if your sortOrder is 'ASC', then this

sortWith([ pose(sortDirection(sortOrder), prop('name')), ])

bees

sortWith([ pose(ascend, prop('name')) ])

which is equivalent to

sortWith([ x => ascend(prop('name')(x)) ])

And the function passed to the sorter is not a proper parator. It is a unary function. The problem is that prop('name') is a unary function, so the pose doesn't do quite what you were hoping.

If you were to rearrange slightly, you could get the correct behavior:

sortWith([ pose(sortDirection(sortOrder), prop)('name'), ], )

this converts, first with ASC, to

sortWith([ pose(ascend, prop)('name'), ], )

and thus to

sortWith([ (x => ascend(prop(x)))('name'), ], )

which is

sortWith([ ascend(prop('name')), ], )

And as we saw, ascend(fn) is a binary parator.

Putting it together

So one way to fix your issues is with

const sortDirection = R.ifElse(R.equals('DESC'), always(descend), always(ascend))
const sortOrder = 'DESC'
sortWith([ pose(sortDirection(sortOrder), prop)('name'), ], data)
//=> [{.. Tim}, {.. Sadie}, {.. Asterios}, {.. Alex}]

And of course if sortOrder = 'ASC', then

sortWith([ pose(sortDirection(sortOrder), prop)('name'), ], data)
//=> [{.. Alex}, {.. Asterios}, {.. Sadie}, {.. Tim}]

Alternate approach

There are two things I still really don't like about the above:

  1. It uses the free variable sortOrder. I would prefer that such variables were parameters to my functions.

  2. It uses sortWith rather than sort. sortWith is a way to bine parator functions. Since we have only one, sort is simpler.

Here's how I might write it to solve those problems:

const {ascend, descend, prop, sort} = R
const data = [{ id: 2, name: 'Asterios' }, { id: 1, name: 'Alex' }, { id: 4, name: 'Tim' }, { id: 3, name: 'Sadie' }]

const sorter = dir => (dir === 'DESC' ? descend : ascend)(prop('name'))

console.log(sort(sorter('DESC'), data))
//=> [{.. Tim}, {.. Sadie}, {.. Asterios}, {.. Alex}]
console.log(sort(sorter('ASC'), data))
//=> [{.. Alex}, {.. Asterios}, {.. Sadie}, {.. Tim}]
<script src="//cdnjs.cloudflare./ajax/libs/ramda/0.25.0/ramda.js"></script>

This doesn't use Ramda but hopefully it gives you an idea on how to start working through the problem

const ascComparator = (a, b) =>
  a < b
    ? -1
    : a > b
      ? 1
      : 0

const descComparator = (a, b) =>
  ascComparator (b, a)

const data =
  [ { id: 2, name: 'Asterios' }
  , { id: 1, name: 'Alex' }
  , { id: 4, name: 'Tim' }
  , { id: 3, name: 'Sadie' }
  ]

data.sort ((a,b) => ascComparator (a.name, b.name))

console.log (data)
// Alex, Asterios, Sadie, Tim

data.sort ((a,b) => descComparator (a.name, b.name))
  
console.log (data)
// Tim, Sadie, Asterios, Alex

The program above demonstrates a beautiful use case for contramap

const contramap = (f, g) =>
  (a, b) =>
    f (g (a), g (b))

const prop = k => o =>
  o [k]

const ascComparator = (a, b) =>
  a < b
    ? -1
    : a > b
      ? 1
      : 0

const descComparator = (a, b) =>
  ascComparator (b, a)

const data =
  [ { id: 2, name: 'Asterios' }
  , { id: 1, name: 'Alex' }
  , { id: 4, name: 'Tim' }
  , { id: 3, name: 'Sadie' }
  ]

data.sort (contramap (ascComparator, prop ('name')))

console.log (data)
// Alex, Asterios, Sadie, Tim

data.sort (contramap (descComparator, prop ('name')))
  
console.log (data)
// Tim, Sadie, Asterios, Alex

localeCompare also works

const ascComparator = (a, b) =>
  a.localeCompare (b)

const descComparator = (a, b) =>
  ascComparator (b, a)

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744780998a4593338.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信