如何在 Ramda 中组成 ascending/descending 排序
How to compose an ascending/descending sort in Ramda
我有一个排序 headers table 的 React 组件。此代码按计划工作:
//definitions and imports...
const [sort, setSort] = useState({column: 'rank', direction: 'ascending', isNumber: true});
const handleSort = (column, isNumber = false) => () => {
let direction = (sort.column !== column) ? 'ascending' : (sort.direction === 'ascending' ? 'descending' : 'ascending');
setSort({column, direction, isNumber});
};
const getSortedData = (data) => {
let sorted = R.sortBy(
R.compose(
sort.isNumber ? Number.parseFloat : R.toLower,
R.prop(sort.column)
),
data
);
return sort.direction === 'ascending' ? sorted : sorted.reverse();
}
//rest of the component...
但是,我确定有一种方法可以使用 R.compose
有条件地 ascend
或 descend
排序(基于 sort.direction
属性 ),因此允许我删除 getSortedData
的最后一行和 reverse
数组操作。
我尝试了几种方法(例如将 ascend
与 prop
组合,在组合中使用条件等),但它们都破坏了代码。
虽然它现在运行良好,但任何人都可以帮我让它变得更 Ramda
ish 吗?
更新 - 为了后代的缘故在这里添加解决方案:
const getSortedData = (data) => {
return R.sort(
(sort.direction === 'ascending' ? R.ascend : R.descend)(
R.compose(
sort.isNumber ? Number.parseFloat : R.toLower,
R.prop(sort.column)
)
)
)(data);
}
我学到的东西:
R.sort
returns 一个函数,而不是一个数组,所以你需要将 data
作为参数发送给整个函数。
R.ascend
/R.descend
也希望函数作为参数,因此不应单独作为 R.compose
的参数。
您可以将 ascend
or descend
与 converge
一起使用:
- 第一个分支确定是升序排序还是降序排序
- 第二个分支确定排序应该在哪个字段(以及哪个转换)上进行操作
const arr = [{a: 10, b: 'ZZZ'}, {a: 5, b: 'ccc'}, {a: 11, b: 'aaa'}];
const makeSort = converge(call, [
({dir}) => dir === 'ascending' ? ascend : descend,
({isNumber, key}) => isNumber ? compose(parseFloat, prop(key)) : compose(toLower, prop(key))]);
const ascSortB = makeSort({dir: 'ascending', isNumber: false, key: 'b'});
const descSortA = makeSort({dir: 'descending', isNumber: true, key: 'a'});
console.log(sort(ascSortB, arr));
console.log(sort(descSortA, arr));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {sort, ascend, descend, prop, converge, call, compose, toLower} = R;</script>
您可能还会发现 有用
我想我会做这样的事情,将 ascend
或 descend
包裹在构图周围:
const makeSorter = (sortConfig) => R.sort (
(sortConfig.direction === 'descending' ? R.descend : R.ascend) ( R.compose (
sortConfig.isNumber ? Number.parseFloat : R.toLower,
R.prop (sortConfig.column)
))
)
const people = [
{name: 'fred', age: 25},
{name: 'barney', age: 28},
{name: 'wilma', age: 29},
{name: 'betty', age: 22}
]
const byName = {direction: 'descending', column: 'name', isNumber: false}
const getSortedData = makeSorter(byName)
console .log (
getSortedData (people)
)
const byAge = {direction: 'ascending', column: 'age', isNumber: true}
console .log (
makeSorter (byAge) (people)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
我个人更喜欢用解构来写它,例如:
const makeSorter = ({direction, isNumber, column}) => R.sort (
(direction === 'descending' ? R.descend : R.ascend) ( R.compose (
isNumber ? Number.parseFloat : R.toLower,
R.prop (column)
))
)
但这并没有改变任何根本性的东西。
我有一个排序 headers table 的 React 组件。此代码按计划工作:
//definitions and imports...
const [sort, setSort] = useState({column: 'rank', direction: 'ascending', isNumber: true});
const handleSort = (column, isNumber = false) => () => {
let direction = (sort.column !== column) ? 'ascending' : (sort.direction === 'ascending' ? 'descending' : 'ascending');
setSort({column, direction, isNumber});
};
const getSortedData = (data) => {
let sorted = R.sortBy(
R.compose(
sort.isNumber ? Number.parseFloat : R.toLower,
R.prop(sort.column)
),
data
);
return sort.direction === 'ascending' ? sorted : sorted.reverse();
}
//rest of the component...
但是,我确定有一种方法可以使用 R.compose
有条件地 ascend
或 descend
排序(基于 sort.direction
属性 ),因此允许我删除 getSortedData
的最后一行和 reverse
数组操作。
我尝试了几种方法(例如将 ascend
与 prop
组合,在组合中使用条件等),但它们都破坏了代码。
虽然它现在运行良好,但任何人都可以帮我让它变得更 Ramda
ish 吗?
更新 - 为了后代的缘故在这里添加解决方案:
const getSortedData = (data) => {
return R.sort(
(sort.direction === 'ascending' ? R.ascend : R.descend)(
R.compose(
sort.isNumber ? Number.parseFloat : R.toLower,
R.prop(sort.column)
)
)
)(data);
}
我学到的东西:
R.sort
returns 一个函数,而不是一个数组,所以你需要将data
作为参数发送给整个函数。R.ascend
/R.descend
也希望函数作为参数,因此不应单独作为R.compose
的参数。
您可以将 ascend
or descend
与 converge
一起使用:
- 第一个分支确定是升序排序还是降序排序
- 第二个分支确定排序应该在哪个字段(以及哪个转换)上进行操作
const arr = [{a: 10, b: 'ZZZ'}, {a: 5, b: 'ccc'}, {a: 11, b: 'aaa'}];
const makeSort = converge(call, [
({dir}) => dir === 'ascending' ? ascend : descend,
({isNumber, key}) => isNumber ? compose(parseFloat, prop(key)) : compose(toLower, prop(key))]);
const ascSortB = makeSort({dir: 'ascending', isNumber: false, key: 'b'});
const descSortA = makeSort({dir: 'descending', isNumber: true, key: 'a'});
console.log(sort(ascSortB, arr));
console.log(sort(descSortA, arr));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {sort, ascend, descend, prop, converge, call, compose, toLower} = R;</script>
您可能还会发现
我想我会做这样的事情,将 ascend
或 descend
包裹在构图周围:
const makeSorter = (sortConfig) => R.sort (
(sortConfig.direction === 'descending' ? R.descend : R.ascend) ( R.compose (
sortConfig.isNumber ? Number.parseFloat : R.toLower,
R.prop (sortConfig.column)
))
)
const people = [
{name: 'fred', age: 25},
{name: 'barney', age: 28},
{name: 'wilma', age: 29},
{name: 'betty', age: 22}
]
const byName = {direction: 'descending', column: 'name', isNumber: false}
const getSortedData = makeSorter(byName)
console .log (
getSortedData (people)
)
const byAge = {direction: 'ascending', column: 'age', isNumber: true}
console .log (
makeSorter (byAge) (people)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
我个人更喜欢用解构来写它,例如:
const makeSorter = ({direction, isNumber, column}) => R.sort (
(direction === 'descending' ? R.descend : R.ascend) ( R.compose (
isNumber ? Number.parseFloat : R.toLower,
R.prop (column)
))
)
但这并没有改变任何根本性的东西。