簡體   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