javascript - 如何以函数式 JS 方式用 Ramda 实现 LoDash 的 sampleSize?
问题描述
我正在尝试用 Ramda以一种功能性的方式实现 LoDash 的sampleSize方法。
有任何想法吗?randomIndex
除了从给定的数组中获取 a 之外,我完全被困住了。如何使用 Ramda 进行递归循环?
所以,函数看起来像这样:
export const sampleSize = curry((size, list) => compose(
// two paths of code
// one to splice messages at the randomIndex
// recursion with the spliced array until length === size
randomIndex
)(list))
解决方案
我可能不会使用 Ramda 来做到这一点。请注意,我是 Ramda 的创始人之一,也是我的忠实粉丝。但是 Ramda 是为函数式编程而设计的。函数式编程的主要原则之一是使用纯函数,即在参数之外不使用任何输入,并且除了返回值之外没有任何效果。对于相同的输入,它们应该总是返回相同的输出。当代码应该随机执行某些操作时,这将不起作用。1
您可以使用类似 lodash 的代码,Fisher-Yates shuffle的早期返回版本,或者您可以使用类似这样的代码,这也将其结果保持在原始数组中的顺序:
const sampleSize = (size, list, collected = []) => size < 1 || list.length < 1
? collected
: size >= list.length
? [...collected, ...list] // or throw error?
: Math.random() < size / list.length
? sampleSize(size -1, list.slice(1), [...collected, list[0]])
: sampleSize(size, list.slice(1), collected)
console.log(sampleSize(4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
console.log(sampleSize(4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
console.log(sampleSize(4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
console.log(sampleSize(0, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
console.log(sampleSize(10, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
console.log(sampleSize(20, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
这是匆忙写的,可能有错误,但应该很接近。这个想法是一次检查每个元素,看看它是否应该被包括在内,根据剩下的数量和列表中剩下的数量来调整机会。
Fisher-Yates 版本会比这更有效,特别是因为它使用了递归,即使在规范已经要求它好几年了,即使在今天,引擎也可能无法有效地优化它。但是 Fisher-Yates 并没有保持原来的排序顺序。如果你想要,这个可能适合你。
1请注意,在某一时刻,Ramda 确实有一个随机数扩展,但它早已被丢弃。它使用了一个可重复的伪随机数生成器,这听起来很矛盾,但在使用纯函数时是有意义的。
推荐阅读
- c++ - 从图像中近似数字厚度的快速算法
- angular - 角度错误处理程序不适用于 500 状态代码
- r - 在 r 中读取一个看起来像稀疏矩阵的 .DAT 文件
- java - 将圈复杂度保持在 5-10 之间是否会使单元测试更容易?
- django - Heroku 与 AWS - 用于部署带有图像的简单网站
- powershell - 当我尝试使用我的 PowerShell 脚本将用户添加到 AD 时出错
- python - Pandas fillna 从均值与 groupby 多列
- powershell - Powershell - 将 Validateset 参数传递到 ForEach-Object 时遇到问题,提示
- javascript - 如何为我自己的 repo 设置依赖项的要求
- powershell - 根据列表禁用 AD 用户