1

我有一个随机的数字 1 到 5 数组,有时会随机出现 [1,1,1,1,2,2] 等。我的任务是始终找到出现次数最多的值。我在这里使用名为 ramda 的库在 javascript 中实现了这一点。阅读文档后,我采用了如下解决方案。

// filter out duplication in array that way you can get the uniq represented numbers
const uniqueItems = R.uniq(params);

// use the unique numbers as keys and create a new array of object
 const mappedItemsWithRepresentations = map((a) => ({ color: a, rep: params.filter(b => b === a).length }), uniqueItems);

// and then finally, select the item with highest rep and return it key
const maxRepItem = mappedItemsWithRepresentations.reduce((acc, curr) => acc.rep > curr.rep ? acc : curr, []);

return maxRepItem.key; // gives me the correct value i need

但是,通过阅读更多文档并浏览此处的示例,我意识到有一种方法可以将上面的逻辑简单地与 ramda 结合起来。我尝试了无数次尝试,我能得到的最接近的是下面。

const getMaxRep = curry(pipe(uniq, map((a) => ({ color: a, rep: filter(b => b === a).length })), pipe(max(pathEq("rep")), tap(console.log))));

console.log("Max Rep here", getMaxRep(params));

我也尝试在这里使用缩减功能,但均无济于事。请我如何安排实现这一目标?任何帮助将不胜感激。

4

3 回答 3

2

Ramda 有 R.countBy 来获取出现次数。您可以将 country 的结果对象转换为对 [value, count],然后将其归约以找到具有最高计数的对:

const { pipe, countBy, identity, toPairs, reduce, maxBy, last, head } = R

const fn = pipe(
  countBy(identity), // count the occurrences 
  toPairs, // convert to pairs of [value, count]
  reduce(maxBy(last), [0, 0]), // reduce to find the maximum occurrence
  head, // get the actual value
  Number, // convert back to an number
)

const arr = [1,1,1,1,2,2]

const result = fn(arr)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>

将具有相同计数的值收集到数组中的想法略有不同。这将处理几个项目的频率相同的情况:

const { pipe, countBy, identity, toPairs, invert, reduce, maxBy, last, head, map } = R

const fn = pipe(
  countBy(identity), // count the occurrences 
  invert, // combine all values with the same count
  toPairs, // convert to pairs of [value, count]
  reduce(maxBy(head), [0, 0]), // reduce to find the maximum occurrence
  last, // get the actual values
  map(Number), // convert back to numbers
)

const arr = [1,1,1,1,2,2,3,3,3,3]

const result = fn(arr)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>

于 2020-04-21T15:44:35.463 回答
1

很好的用例,试试这个:

const maxReduce = reduce(maxBy(last), [0,0])
const getMaxRep = pipe(countBy(identity), toPairs, maxReduce, head)

console.log(getMaxRep([1,1,1,1,2,2]))

countBy 是一个非常好的开始,遗憾的是 Ramda 不支持对象的 reduce,但我们可以使用 toPairs 函数转换为数组数组并完成工作。

于 2020-04-21T16:02:26.937 回答
1

我不完全清楚你要的是什么。

但它可能是这样的:

const maxRep = pipe (
  countBy (identity),
  toPairs,
  map (zipObj(['color', 'rep'])), 
  reduce (maxBy (prop ('rep')), {rep: -Infinity}),
)

const params = [1, 2, 3, 4, 2, 3, 5, 2, 3, 2, 1, 1, 4, 5, 5, 3, 2, 5, 1, 5, 2]

console .log (
  maxRep (params)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
<script> const {pipe, countBy, identity, toPairs, map, zipObj, reduce, maxBy, prop} = R </script>

我们从一个从 中抽取的值列表开始,这些值{1, 2, 3, 4, 5}以某种随机的、多次出现的顺序出现。

随着countBy(identity)我们将原始列表更改为类似

{"1": 4, "2": 6, "3": 4, "4": 2, "5": 5}

与每个条目关联的计数。

toPairs将其格式化为数组

[["1", 4], ["2", 6], ["3", 4], ["4", 2], ["5", 5]]

(你也可以Object.entries在这里使用。)

然后通过调用map (zipObj (['color', 'rep'])),我们把它变成

[{"color": "1", "rep": 4}, {"color": "2", "rep": 6}, ...]

最后,我们使用 减少结果,maxBy (prop ('rep'))它选择具有最大代表值的那个。对于 max 调用的初始值,我们创建了一个虚拟对象,{rep: -Infinity}它将比您列表中的任何一个都少。

如果您还想保留最终的中间结构,您可以将该函数重命名为makeReps,删除管道中的最后一个函数,然后从中创建一个新函数maxRep

然后你可以打电话

const reps = makeResps (params)
const maxVal = maxRep (reps)

并使用两者。

但是所有这些都假设colorrep属性的值是您需要的。如果您只需要计数,那么这里已经存在的其他解决方案可以处理得很好。

于 2020-04-21T16:03:54.823 回答