[英]How to write an F# union type chooser?
如果使用F#,還有更好的方法嗎?
type T =
| A of int
| B of string
static member chooseA x = match x with A i -> Some i | _ -> None
static member chooseB x = match x with B s -> Some s | _ -> None
用例如下:
let collection = [A 10; B "abc"]
let aItems = collection |> Seq.choose T.chooseA
let bItems = collection |> Seq.choose T.chooseB
謝謝!
使用List.partition拆分源元素:
type T =
| A of int
| B of string
let collection = [A 10; B "abc"; A 40; B "120"]
let result = List.partition (function | A _ -> true | _ -> false) collection
val result : T list * T list = ([A 10; A 40], [B "abc"; B "120"])
然后,您可以使用fst和snd選擇相關列表。
這很尷尬,但是我可以理解為什么它不是F#設計的重要案例。 通常,有一種解決方案允許完整的模式匹配,而不是多個(有些不完整)的模式匹配。 例如,可以這樣構造兩個具體的項目序列:
let aItems, bItems =
let accA, accB = ResizeArray(), ResizeArray()
collection |> Seq.iter (function A i -> accA.Add i | B s -> accB.Add s)
seq accA, seq accB
如果您不喜歡,可以采用類似的無突變解決方案,但是我幾乎沒有理由擔心封裝突變。 請注意,結果強制轉換為seq
。
這將按照其設計方式使用模式匹配:
T
,則處理功能中將顯示一條警告,這正是繼續編輯的地方:確定如何處理新輸入的大小寫。 如果上述方法不合適,您仍然可以通過使用function
關鍵字並將聲明選擇器函數聲明為lambda來稍微縮短問題的代碼。 例如:
let aItems = collection |> Seq.choose (function A i -> Some i | _ -> None)
請注意,這是惰性的,就像問題中的建議一樣:在這里,對aItems
每次迭代aItems
將不必要地遍歷輸入中的所有B
例。
我可以提供以下變體:
open System.Reflection
type T =
| A of int
| B of string
let collection = [A 10; B "abc"; A 40; B "120"]
let sp (col: T list) (str:string) =
if col=[] then []
else
let names = "Is" + str
col |> List.filter(fun x-> let t = x.GetType()
if t.GetProperty(names) = null then false
else
t.InvokeMember(names, BindingFlags.GetProperty, null, x, null) :?> bool)
|> List.map(fun y ->
y.GetType().InvokeMember("get_Item", BindingFlags.InvokeMethod, null, y, null))
sp collection "A" |> printfn "%A\n"
sp collection "B" |> printfn "%A\n"
sp collection "C" |> printfn "%A\n"
打印:
[10; 40]
["abc"; "120"]
[]
我是F#的新手,所以我認為這可以輕松完成
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.