繁体   English   中英

如何以功能性JS方式使用Ramda实现LoDash的sampleSize?

[英]How to implement LoDash's sampleSize with Ramda in a functional JS way?

我正在尝试以功能性的方式通过Ramda实现LoDash的sampleSize方法。

有任何想法吗? randomIndex从给定数组中获取randomIndex之外,我完全randomIndex任何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是为函数式编程而设计的。 函数式编程的主要宗旨之一是使用纯函数,纯函数在其参数外不使用任何输入,并且除了返回值外没有其他作用。 对于相同的输入,它们应该始终返回相同的输出。 当代码应该随机执行某项操作时,这将不起作用。 1

您可以使用类似lodash的代码,早期返回的Fisher-Yates混编版本,也可以使用类似的代码,这样也可以使结果保持原始数组中的顺序:

 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确实确实有一个随机数扩展名 ,但长期以来一直被丢弃。 它使用了可重复的伪随机数生成器,听起来似乎很矛盾,但是在使用纯函数时才有意义。

首先让我们定义一个函数,该函数将返回一个介于min (含)和max (不含)之间的随机数。 我们可以咖喱它,因为min总是设置为0,而max总是设置为新列表的长度-1

const random = curry((min, max) => Math.floor(Math.random() * (max - min) - min));

然后,我们需要一个函数,该函数将获取一个列表并返回两件事(在数组中):

  1. 随机选择的元素
  2. 没有该元素的新列表
const takeFromList = converge(
  converge(pair, [nth, flip(remove)(1)]) [compose(random(0), length), identity]);

将所有内容放在一起:

如您所见,如果请求的样本大小大于实际列表大小,它将以随机顺序返回整个列表。

 const {curry, min, nth, identity, converge, pair, flip, compose, length, remove, flatten} = R; const random = curry((min, max) => Math.floor(Math.random() * (max - min) - min)); const takeFromList = converge(converge(pair, [nth, flip(remove)(1)]), [compose(random(0), length), identity]); const sampleSize = curry((size, list) => { const [el, newList] = takeFromList(list); const len = min(size, list.length); return len - 1 > 0 ? flatten([el, sampleSize(len - 1, newList)]) : [el]; }); console.log(sampleSize(2, [1,2,3,4,5])); console.log(sampleSize(2, [1,2,3,4,5])); console.log(sampleSize(2, [1,2,3,4,5])); console.log(sampleSize(20, [1,2,3,4,5])); console.log(sampleSize(20, [1,2,3,4,5])); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM