[英]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.