【问题标题】:How to compose an ascending/descending sort in Ramda如何在 Ramda 中组成升序/降序排序
【发布时间】:2019-06-06 01:05:12
【问题描述】:

我有一个带有排序标题表的 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 属性),从而允许我删除@987654326 的最后一行@ 和 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 返回一个函数,而不是数组,因此您需要将 data 作为参数发送给整个函数。
  2. R.ascend/R.descend 也期望该函数作为参数,因此不应单独作为 R.compose 的参数。

【问题讨论】:

  • 你的两个学习都有些偏离。 (1) sort 返回排序后的数组,但就像所有 Ramda 函数都是柯里化的,所以如果你在第一次调用时没有提供数组,你会得到一个等待它的新函数。事实上,在本例中,将)(data) 替换为, data) 会稍微好一些。 (2) ascenddescendcompose 中很好,但传递给它们的值必须是返回某种有序类型元素的函数(可以通过 < 合理地比较)。可以使用嵌套的 compose 函数轻松编写。
  • 另请注意,写getSortedData 意味着每次使用时都必须构建主函数。那里没有太多事情发生,所以它可能不是什么大问题,但如果你把它拉到一个单独的函数中,它可能是可重用的。
  • @ScottSauyet 实际上我来这里是想看看如何使用compose 来组合它——如果你有建议,我很高兴听到。我尝试将data 作为参数传递给排序,但出现了某种错误——我会再调查一次。最后,我理解你所说的关于重建函数的内容——我将对其进行重构,以便它可以被重用。谢谢!

标签: javascript sorting ramda.js


【解决方案1】:

我想我会做这样的事情,将 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)
  ))
)

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

【讨论】:

  • 是的!这正是我一直在寻找的!我用你的答案组成了最终版本——为了后代,我会把它贴在问题中。干杯伙伴!
【解决方案2】:

您可以将ascenddescendconverge 一起使用:

  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>

您可能还会发现this post 很有用

【讨论】:

  • 我知道我可以这样使用它 - 我正在尝试将它组合到现有函数中。
  • 您正在手动恢复排序,而如果您将ascenddescendsort 结合使用(而不是sortBy),则不需要这样做。跨度>
  • 但我同意你的观点,即尝试组合你的不同标准。将发布更新。
  • sortsortBysortWith 存在一些真正的混淆,我真的不知道如何在 Ramda 文档中解决。
猜你喜欢
  • 1970-01-01
  • 2015-03-09
  • 2015-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-24
相关资源
最近更新 更多