[英]How can I make this code more 'functional programming' style in Ramda.js / lodash
[英]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));
然后,我們需要一個函數,該函數將獲取一個列表並返回兩件事(在數組中):
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.