如何在 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 有条件地 ascenddescend 排序(基于 sort.direction 属性 ),因此允许我删除 getSortedData 的最后一行和 reverse 数组操作。

我尝试了几种方法(例如将 ascendprop 组合,在组合中使用条件等),但它们都破坏了代码。

虽然它现在运行良好,但任何人都可以帮我让它变得更 Ramdaish 吗?

更新 - 为了后代的缘故在这里添加解决方案:

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);
}

我学到的东西:

  1. R.sort returns 一个函数,而不是一个数组,所以你需要将 data 作为参数发送给整个函数。
  2. R.ascend/R.descend 也希望函数作为参数,因此不应单独作为 R.compose 的参数。

您可以将 ascend or descendconverge 一起使用:

  1. 第一个分支确定是升序排序还是降序排序
  2. 第二个分支确定排序应该在哪个字段(以及哪个转换)上进行操作

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>

您可能还会发现 有用

我想我会做这样的事情,将 ascenddescend 包裹在构图周围:

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)
  ))
)

但这并没有改变任何根本性的东西。