代码之家  ›  专栏  ›  技术社区  ›  corvid

使用ramda通过变量进行升序/降序

  •  0
  • corvid  · 技术社区  · 6 年前

    我有一个要按名称排序的用户列表。列表如下所示:

    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')), ])
    

    是否有一种通过变量应用这种升序/降序排序逻辑的好方法?

    2 回复  |  直到 6 年前
        1
  •  6
  •   Scott Sauyet    6 年前

    好的,这里有几个小问题。然而,调试一个大问题通常比调试几个小问题更容易。

    使用 ifElse 正确地

    第一个是使用 如果其他 。这将三个函数作为参数,并返回一个新函数,该函数根据使用参数调用第一个函数的结果, 呼叫 具有这些参数的第二个或第三个函数。请注意,它不会返回函数;它叫它。有几种方法可以解决此问题。您可以将这些函数包装为 always :

    const sortDirection = R.ifElse(R.equals('DESC'), always(descend), always(ascend))
    

    但我认为放弃point free和使用

    const sortDirection = dir => (dir === 'DESC' ? descend : ascend)
    

    理解力 compose

    其次,您将一个稍有错误的值传递到 ascend descend .虽然这还不是很好的实现,但想想 上升 就像

    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') 是一元函数,因此 组成 没有达到你的期望。

    如果稍微重新排列,您可以获得正确的行为:

    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}]
    

    备用进近

    对于上述内容,有两件事我仍然很不喜欢:

    1. 它使用自由变量 排序器 。我希望这些变量是我函数的参数。

    2. 它使用 sortWith公司 而不是 sort sortWith公司 是一种 结合 比较器功能。因为我们只有一个, 分类 更简单。

    我可以这样写来解决这些问题:

    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>
        2
  •  2
  •   Mulan    6 年前

    这并不使用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)