[英]Filter an array against another array/string conditionally in Ramda
我正在練習 Ramda,並嘗試構建一個 function 如下:
function 需要兩個參數:
userInput: {
query: Array[String] || String,
target: Array[String]
}
目標:
例如:如果目標是:
["pen", "pencil", "paper", "", undefined, True, "books", "paperback"]
查詢是:
["pen", "paper"]
那么過濾后的結果應該是:
["pen", "pencil", "paper", "paperback"]
我已經以普通/香草(?)js方式實現了目標。 但這不一定是 FP,也不是利用 Ramda。
到目前為止,我的實驗是這樣的:
startsWith
);any
或anyPass
); 在代碼方面,我正在考慮使用map
或apply
startsWith
function 應用於目標數組的每個元素。 到目前為止,我只這樣做了:
const textStartsWith = curry((query, target) =>
pipe(toString, startsWith(query))(target)
);
但是,我被困在這里對函數的組合進行了柯里化。
任何幫助將非常感激!
我會像這樣結合startsWith
和anyPass
:
const textStartsWith = pipe ( map (startsWith), anyPass, flip (o) (String), filter ) console.log ( textStartsWith (['pen', 'paper']) (['pen', 'pencil', 'paper', '', undefined, true, 'books', 'paperback']) )
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script> <script>const {pipe, map, startsWith, anyPass, flip, o, filter} = R </script>
如果您希望能夠在一個 go 中通過 arguments,您可以將其包裝在uncurry
中:
const textStartsWith = uncurryN (2) (pipe (
map (startsWith),
anyPass,
flip (o) (String),
filter
))
textStartsWith (query, target)
我認為這確實指出了 Ramda 中缺少的 function。 Ramda 具有可變參數compose
和pipe
函數,以及 curried 二進制 compose, o
。 但是沒有等效的咖喱二進制pipe
。
One possible way to arrive at such an implementation is to make a fully curried function, and then paste a Haskell equivalent into http://pointfree.io .
所以如果我們從這個 function 開始:
const f1 = (query) => (target) => filter (pipe (
String,
anyPass (map( startsWith) (query))
)) (target)
我們可以像這樣制作 Haskell 版本:
\query -> \target -> filter ((anyPass ((map startsWith) query)) . string) target
然后返回:
filter . (. string) . anyPass . map startsWith
我們可以像上面第一個答案一樣通過注意foo. bar
foo. bar
是foo
和bar
的組合,而(. foo)
等價於flip (o) (foo)
或o (__, foo)
我們最終可以得到類似於上面第一個片段的內容。
用戶 Kuncheria 詢問了flip (o) (String)
。 也許瀏覽簽名可能會有所幫助。 我們將四個函數傳遞給 pipe。
map (startsWith)
具有簽名[String] -> [(String -> Boolean)]
。 它接受一個字符串列表並將函數列表從字符串返回到 Boolean。
anyPass
具有簽名[(a -> Boolean)] -> (a -> Boolean)
。 它從某個任意類型( a
到Boolean
)獲取函數列表,並從a
到 Boolean 返回單個Boolean
(對於提供的函數中的a
,這將是true
的)。
Now we can combine the output of map (startsWith)
( [(String -> Boolean)]
with the input to anyPass
, by substituting String
for a
, and so pipe (map (startsWith), anyPass))
has the signature [String] -> (String -> Boolean)
。
flip (o) (String)
這里是最復雜的function,下面我們會解釋。 在那里我們會發現它的類型是(String -> c) -> (a -> c)
。
And now substituting Boolean
for c
, we combine with the above to to see that pipe (map (startsWith), anyPass, flip (o) (String))
has the signature [String] -> (a -> Boolean)
.
filter
僅具有簽名(a -> Boolean) -> [a] -> [a]
。 It accepts a function that transforms a value of type a
into a boolean, and returns a function that takes a list of values of type a
and returns the filtered list of those for which the function returns true
.
所以結合上面的,我們可以注意到我們的主要 function -- pipe (map (startsWith), anyPass, flip (o) (String), filter)
-- 有簽名[String] -> [a] -> [a]
我們可以把上面的討論寫得更簡潔:
const textStartsWith = pipe (
map (startsWith), // [String] -> [(String -> Boolean)]
anyPass, // [(a -> Boolean)] -> (a -> Boolean)
// a = String => [String] -> (String -> Boolean)
flip (o) (String), // (String -> c) -> (a -> c)
// c = Boolean => [String] -> (a -> Boolean)
filter // (a -> Boolean) -> [a] -> [a]
// => [String] -> [a] -> [a]
)
但是我們仍然需要討論flip (o) (String)
。
o
是一個 curried 二進制compose
function,其簽名是
o :: (b -> c) -> (a -> b) -> (a -> c)
我們可以flip
它,得到:
flip (o) :: (a -> b) -> (b -> c) -> (a -> c)
現在我們遇到了一個符號問題。 我們一直在使用String
來表示 String 類型。 但是在 JS 中, String
也是一個 function:用任何值構造一個 String。 我們可以將其視為從某種類型a
到字符串的 function,即類型a -> String
。 所以,既然
flip (o) :: (a -> b) -> (b -> c) -> (a -> c)
我們可以看到:
flip (o) (String)
; ^----------------- Constructor function
flip (o) (a -> String)
; ^------------ Data type
flip (o) (String) :: (String -> c) -> (a -> c)
; ^ ^----- Data type
; +----------------- Constructor function
We can think of flip (o) (String)
as a function that accepts a function which transforms a String into type c
, and returns a function which transforms something of type a
into something of type c
. 一個例子是length
, function 采用字符串的長度:
const strLength = flip (o) (String) (length)
strLength ('abc') //=> 3 because String ('abc') = 'abc'
strLength (42) //=> 2 because String (42) = '42'
strLength (void 0) //=> 9 because String (void 0) = 'undefined'
strLength ({}) //=> 15 because String ({}) = 'object [Object]'
如果query
不是數組,則將其轉換為數組(請參閱convertToArray
)。 Map query
,並使用R.startsWith
創建一個測試數組。 過濾target
,並使用R.anyPass
作為謂詞:
const { curry, unless, is, of, filter, anyPass, map, startsWith } = R; const convertToArray = unless(is(Array), of); const textStartsWith = curry((query, target) => filter(anyPass(map(startsWith, convertToArray(query))))(target) ); const query = ["pen", "paper"]; const target = ["pen", "pencil", "paper", "", "books", "paperback"]; const result = textStartsWith(query, target); console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
如果您需要處理非字符串值,我會為每個不是字符串的值返回false
。 請注意,使用R.toString
轉換字符串會轉換字符串 - R.toString('abc'); //=> '"abc"'
R.toString('abc'); //=> '"abc"'
(參見文檔)
const { curry, unless, is, of, filter, ifElse, anyPass, map, startsWith, always } = R; const convertToArray = unless(is(Array), of); const textStartsWith = curry((query, target) => filter(ifElse( is(String), anyPass(map(startsWith, convertToArray(query))), always(false) ))(target) ); const query = ["pen", "paper"]; const target = ["pen", "pencil", "paper", "", undefined, true, "books", "paperback"]; const result = textStartsWith(query, target); console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.