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 badges2 Answers
Reset to default 6Ok, 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:
It uses the free variable
sortOrder
. I would prefer that such variables were parameters to my functions.It uses
sortWith
rather thansort
.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条)