如何使用Ramda JS获得排序列表中每组的前n个元素

问题描述 投票:0回答:1

我对RamdaJS和函数式编程还很陌生,所以我希望了解是否有更有效的方法来实现以下目标。

假设我有一个足球运动员名单。列表中的每个足球运动员都具有其姓名,球队和月薪的属性。

const footballers = [
  {
    name: "Mesut Ozil",
    team: "Arsenal",
    pay: 1400000
  },
  {
    name: "Lionel Messi",
    team: "Barcelona",
    pay: 7300000
  },
  {
    name: "Kylian Mbappe",
    team: "PSG",
    pay: 1500000
  },
  {
    name: "Alexis Sanchez",
    team: "Manchester United",
    pay: 1990000
  },
  {
    name: "Philippe Coutinho",
    team: "Barcelona",
    pay: 2000000
  },
  {
    name: "Neymar",
    team: "PSG",
    pay: 2700000
  },
  {
    name: "Luis Suarez",
    team: "Barcelona",
    pay: 2500000
  },
  {
    name: "Antoine Griezmann",
    team: "Atletico Madrid",
    pay: 2900000
  },
  {
    name: "Gareth Bale",
    team: "Real Madrid",
    pay: 2200000
  },
  {
    name: "Cristiano Ronaldo",
    team: "Juventus",
    pay: 4100000
  }
]

我希望按薪水排序此列表,但在最终列表中,每支球队最多只能有两名球员。目前,我的解决方案必须对列表进行两次排序。目前,它在列表的开头和后面进行排序,但也可以在按团队分组之后进行排序。我相信有一个更聪明(但仍可读)的解决方案,只需要一种解决方案,但我不确定它是什么。

const byPayAsc = ascend(prop('pay')) // spare, for checking
const byPayDes = descend(prop('pay'))
const sortByPay = sort(byPayDes)

const groupedByTeam = compose(values, groupBy(prop('team')))
const topTwoPlayers = map(take(2))

const topTwoHighestPaidPlayersPerTeam = pipe( 
  sortByPay,
  groupedByTeam, 
  topTwoPlayers, 
  flatten, 
  sortByPay
)

topTwoHighestPaidPlayersPerTeam(footballers)

我目前的调查发现了一些选择:

  • 我听说过换能器,我认为它可能提供仅循环浏览列表一次的好处。
  • 我还想知道是否可以使用排序功能合并分组列表?
  • 或者我可以编写一个reducer来遍历列表列表并获取每个团队的前2名。

使用Ramda JS的惯用方式是什么。

javascript functional-programming ramda.js
1个回答
0
投票

您重新排序的想法是正确的,因为按团队对玩家进行分组会更改初始排序。

如果要跳过第二种排序,则需要保留每个项目的原始索引,然后无论如何都要按索引排序。所以我不确定是否值得。

但是,为了检查这个主意,此代码段将数组项在排序之后但在由玩家团队进行分组之前转换为成对的[index,player]。当使用R.values和R.chain(带有R.take)将组平整到数组时,可以使用R.fromPairs将对转换回对象。由于对整数对象键的ES6遍历是递增的,因此恢复了原始顺序,现在您可以通过再次调用R.values获得数组。

const { pipe, sort, descend, prop, toPairs, groupBy, path, values, chain, take, fromPairs } = R

const topTwoHighestPaidPlayersPerTeam = pipe( 
  sort(descend(prop('pay'))), // sort descending by pay
  toPairs, // convert to pairs if [index, player object]
  groupBy(path([1, 'team'])), // group by the team
  values, // get an array of an arrays 
  chain(take(2)), // flatten and take the 1st two items of each group
  fromPairs, // convert to an object of objects with original index as key
  values // convert to an array in the correct order
)

const footballers = [{"name":"Mesut Ozil","team":"Arsenal","pay":1400000},{"name":"Lionel Messi","team":"Barcelona","pay":7300000},{"name":"Kylian Mbappe","team":"PSG","pay":1500000},{"name":"Alexis Sanchez","team":"Manchester United","pay":1990000},{"name":"Philippe Coutinho","team":"Barcelona","pay":2000000},{"name":"Neymar","team":"PSG","pay":2700000},{"name":"Luis Suarez","team":"Barcelona","pay":2500000},{"name":"Antoine Griezmann","team":"Atletico Madrid","pay":2900000},{"name":"Gareth Bale","team":"Real Madrid","pay":2200000},{"name":"Cristiano Ronaldo","team":"Juventus","pay":4100000}]

const result = topTwoHighestPaidPlayersPerTeam(footballers)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
© www.soinside.com 2019 - 2024. All rights reserved.