使用 ramda 通过变量获取 ascending/descending
Get ascending/descending by a variable with ramda
我有一个要按名称排序的用户列表。该列表如下所示:
const data = [
{ id: 2, name: 'Asterios' },
{ id: 1, name: 'Alex' },
{ id: 4, name: 'Tim' },
{ id: 3, name: 'Sadie' },
]
我实现了一个相对简单的选择器,它将根据一些 属性.
对用户列表进行排序
const getUserList = createSelector(
getUsers,
getSortBy,
getSortOrder,
(users, sortBy, sortOrder) => R.sortWith([
R.ascend(R.prop(sortBy)),
])(users),
);
但是,我想使用变量 sortOrder
,它可以是 'ASC'
或 'DESC'
,并应用该排序顺序。
我试过这样的事情:
const sortDirection = R.ifElse(R.equals('DESC'), descend, ascend);
sortWith([ compose(sortDirection(sortOrder), prop('name')), ])
是否有通过变量应用此 ascending/descending 排序逻辑的好方法?
这不使用 Ramda,但希望它能让您了解如何开始解决问题
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
上面的程序演示了 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
也有效
const ascComparator = (a, b) =>
a.localeCompare (b)
const descComparator = (a, b) =>
ascComparator (b, a)
好的,你这里有几个小问题。不过,调试一个大问题通常比调试几个小问题更容易。
正确使用ifElse
第一个是ifElse
的使用。这需要三个函数作为参数,returns 一个新函数,根据用你的参数调用第一个函数的结果,调用第二个或第三个函数争论。请注意,它没有 return 功能;它叫它。有几种方法可以解决这个问题。您可以使用 always
:
包装这些函数
const sortDirection = R.ifElse(R.equals('DESC'), always(descend), always(ascend))
但我认为放弃无积分并使用
更简单
const sortDirection = dir => (dir === 'DESC' ? descend : ascend)
了解compose
其次,您向 ascend
或 descend
传递了一个稍微错误的值。虽然这不是完全的实现,但可以将 ascend
视为类似
的东西
const ascend = curry(fn, a, b) => fn(a) < fn(b) ? -1 : fn(a) > fn(b) ? 1 : 0);
请注意,如果您将一元函数传递给它,例如 fn = prop('name')
,您将返回 (a, b) => fn(a) < fn(b) ? -1 : fn(a) > fn(b) ? 1 : 0
,这是一个二元比较器函数。 sortWith
接受比较器列表。这样就好了。
但是如果你的sortOrder
是'ASC'
,那么这个
sortWith([ compose(sortDirection(sortOrder), prop('name')), ])
变成
sortWith([ compose(ascend, prop('name')) ])
相当于
sortWith([ x => ascend(prop('name')(x)) ])
而且传递给排序器的函数不是一个合适的比较器。它是一个一元函数。问题是 prop('name')
是一个一元函数,所以 compose
并没有达到您的预期。
如果稍微重新排列,您可以获得正确的行为:
sortWith([ compose(sortDirection(sortOrder), prop)('name'), ], )
这将首先使用 ASC
转换为
sortWith([ compose(ascend, prop)('name'), ], )
因此
sortWith([ (x => ascend(prop(x)))('name'), ], )
即
sortWith([ ascend(prop('name')), ], )
正如我们所见,ascend(fn)
是一个二进制比较器。
放在一起
所以解决问题的一种方法是
const sortDirection = R.ifElse(R.equals('DESC'), always(descend), always(ascend))
const sortOrder = 'DESC'
sortWith([ compose(sortDirection(sortOrder), prop)('name'), ], data)
//=> [{.. Tim}, {.. Sadie}, {.. Asterios}, {.. Alex}]
当然,如果 sortOrder = 'ASC'
,那么
sortWith([ compose(sortDirection(sortOrder), prop)('name'), ], data)
//=> [{.. Alex}, {.. Asterios}, {.. Sadie}, {.. Tim}]
替代方法
关于上面的内容,有两点我仍然非常不喜欢:
它使用自由变量sortOrder
。我更希望这些变量是我函数的参数。
它使用sortWith
而不是sort
。 sortWith
是 组合 比较器函数的一种方式。因为我们只有一个,所以sort
更简单。
下面是我可能会如何编写它来解决这些问题:
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.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
我有一个要按名称排序的用户列表。该列表如下所示:
const data = [
{ id: 2, name: 'Asterios' },
{ id: 1, name: 'Alex' },
{ id: 4, name: 'Tim' },
{ id: 3, name: 'Sadie' },
]
我实现了一个相对简单的选择器,它将根据一些 属性.
对用户列表进行排序const getUserList = createSelector(
getUsers,
getSortBy,
getSortOrder,
(users, sortBy, sortOrder) => R.sortWith([
R.ascend(R.prop(sortBy)),
])(users),
);
但是,我想使用变量 sortOrder
,它可以是 'ASC'
或 'DESC'
,并应用该排序顺序。
我试过这样的事情:
const sortDirection = R.ifElse(R.equals('DESC'), descend, ascend);
sortWith([ compose(sortDirection(sortOrder), prop('name')), ])
是否有通过变量应用此 ascending/descending 排序逻辑的好方法?
这不使用 Ramda,但希望它能让您了解如何开始解决问题
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
上面的程序演示了 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
也有效
const ascComparator = (a, b) =>
a.localeCompare (b)
const descComparator = (a, b) =>
ascComparator (b, a)
好的,你这里有几个小问题。不过,调试一个大问题通常比调试几个小问题更容易。
正确使用ifElse
第一个是ifElse
的使用。这需要三个函数作为参数,returns 一个新函数,根据用你的参数调用第一个函数的结果,调用第二个或第三个函数争论。请注意,它没有 return 功能;它叫它。有几种方法可以解决这个问题。您可以使用 always
:
const sortDirection = R.ifElse(R.equals('DESC'), always(descend), always(ascend))
但我认为放弃无积分并使用
更简单const sortDirection = dir => (dir === 'DESC' ? descend : ascend)
了解compose
其次,您向 ascend
或 descend
传递了一个稍微错误的值。虽然这不是完全的实现,但可以将 ascend
视为类似
const ascend = curry(fn, a, b) => fn(a) < fn(b) ? -1 : fn(a) > fn(b) ? 1 : 0);
请注意,如果您将一元函数传递给它,例如 fn = prop('name')
,您将返回 (a, b) => fn(a) < fn(b) ? -1 : fn(a) > fn(b) ? 1 : 0
,这是一个二元比较器函数。 sortWith
接受比较器列表。这样就好了。
但是如果你的sortOrder
是'ASC'
,那么这个
sortWith([ compose(sortDirection(sortOrder), prop('name')), ])
变成
sortWith([ compose(ascend, prop('name')) ])
相当于
sortWith([ x => ascend(prop('name')(x)) ])
而且传递给排序器的函数不是一个合适的比较器。它是一个一元函数。问题是 prop('name')
是一个一元函数,所以 compose
并没有达到您的预期。
如果稍微重新排列,您可以获得正确的行为:
sortWith([ compose(sortDirection(sortOrder), prop)('name'), ], )
这将首先使用 ASC
转换为
sortWith([ compose(ascend, prop)('name'), ], )
因此
sortWith([ (x => ascend(prop(x)))('name'), ], )
即
sortWith([ ascend(prop('name')), ], )
正如我们所见,ascend(fn)
是一个二进制比较器。
放在一起
所以解决问题的一种方法是
const sortDirection = R.ifElse(R.equals('DESC'), always(descend), always(ascend))
const sortOrder = 'DESC'
sortWith([ compose(sortDirection(sortOrder), prop)('name'), ], data)
//=> [{.. Tim}, {.. Sadie}, {.. Asterios}, {.. Alex}]
当然,如果 sortOrder = 'ASC'
,那么
sortWith([ compose(sortDirection(sortOrder), prop)('name'), ], data)
//=> [{.. Alex}, {.. Asterios}, {.. Sadie}, {.. Tim}]
替代方法
关于上面的内容,有两点我仍然非常不喜欢:
它使用自由变量
sortOrder
。我更希望这些变量是我函数的参数。它使用
sortWith
而不是sort
。sortWith
是 组合 比较器函数的一种方式。因为我们只有一个,所以sort
更简单。
下面是我可能会如何编写它来解决这些问题:
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.com/ajax/libs/ramda/0.25.0/ramda.js"></script>