我正在尝试实现 LoDash 的 sampleSize以函数式方式使用 Ramda 的方法。
有什么想法吗?除了从给定数组中获取 randomIndex
之外,我完全陷入困境。如何使用 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 的忠实粉丝。但 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 确实有 random number extension ,但这早已被废弃了。它使用了可重复的伪随机数生成器,这听起来几乎像是矛盾的说法,但在使用纯函数时是有意义的。
关于javascript - 如何以函数式JS方式使用Ramda实现LoDash的sampleSize?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54274045/