从列表映射到另一种类型——有更好的方法吗?
Map from a list to another type - Is there a better way to do this?
let claimsList =
[ {|cType = "uid"; cValue="1"|};
{|cType = "name"; cValue="N1"|};
{|cType = "sid"; cValue="sid1"|};
{|cType = "email"; cValue="email@N1.com"|};
{|cType = "company"; cValue="Company1"|}]
let email = claimsList
|> List.tryFind(fun c -> c.cType = "email")
|> Option.map(fun c -> c.cValue)
let company = claimsList
|> List.tryFind(fun c -> c.cType = "company")
|> Option.map(fun c -> c.cValue)
let userId = claimsList
|> List.tryFind(fun c -> c.cType = "userId")
|> Option.map(fun c -> c.cValue)
(email, userId, company)
我不喜欢我多次迭代列表并且看起来很复杂的事实。有没有办法简化这个?
您可以通过使用折叠来避免多次迭代,但它不一定会变得不那么复杂:
let claimsList =
[ {|cType = "uid"; cValue="1"|};
{|cType = "name"; cValue="N1"|};
{|cType = "sid"; cValue="sid1"|};
{|cType = "email"; cValue="email@N1.com"|};
{|cType = "company"; cValue="Company1"|}]
let fld cur (n : {| cType: string; cValue: string |}) =
let (a,b,c) = cur
match n.cType with
| "email" -> (Some n.cValue, b, c)
| "userId" -> (a, Some n.cValue, c)
| "company" -> (a, b, Some n.cValue)
| _ -> cur
claimsList
|> List.fold fld (None, None, None)
主要优点是消除了多个列表迭代,尤其是在列表很大的情况下。
如果您需要多次查找索赔,并且假设它们都有不同的 cType
,您可以将列表转换为地图,然后在其中查找:
let map = claimsList |> List.map (fun r -> r.cType, r.cValue) |> Map.ofList
let email = map.["email"]
let company = map.["company"]
let userId = map.["uid"]
请注意,如果键不存在于映射中,像 map.["email"]
这样的索引将在运行时崩溃。如果丢失键“通常不应该发生”,这很好,但是如果你想优雅地处理这种情况,请改用 Map.tryFind
,这将 return 你 option
:
let email = map |> Map.tryFind "email"
let claimsList =
[ {|cType = "uid"; cValue="1"|};
{|cType = "name"; cValue="N1"|};
{|cType = "sid"; cValue="sid1"|};
{|cType = "email"; cValue="email@N1.com"|};
{|cType = "company"; cValue="Company1"|}]
let email = claimsList
|> List.tryFind(fun c -> c.cType = "email")
|> Option.map(fun c -> c.cValue)
let company = claimsList
|> List.tryFind(fun c -> c.cType = "company")
|> Option.map(fun c -> c.cValue)
let userId = claimsList
|> List.tryFind(fun c -> c.cType = "userId")
|> Option.map(fun c -> c.cValue)
(email, userId, company)
我不喜欢我多次迭代列表并且看起来很复杂的事实。有没有办法简化这个?
您可以通过使用折叠来避免多次迭代,但它不一定会变得不那么复杂:
let claimsList =
[ {|cType = "uid"; cValue="1"|};
{|cType = "name"; cValue="N1"|};
{|cType = "sid"; cValue="sid1"|};
{|cType = "email"; cValue="email@N1.com"|};
{|cType = "company"; cValue="Company1"|}]
let fld cur (n : {| cType: string; cValue: string |}) =
let (a,b,c) = cur
match n.cType with
| "email" -> (Some n.cValue, b, c)
| "userId" -> (a, Some n.cValue, c)
| "company" -> (a, b, Some n.cValue)
| _ -> cur
claimsList
|> List.fold fld (None, None, None)
主要优点是消除了多个列表迭代,尤其是在列表很大的情况下。
如果您需要多次查找索赔,并且假设它们都有不同的 cType
,您可以将列表转换为地图,然后在其中查找:
let map = claimsList |> List.map (fun r -> r.cType, r.cValue) |> Map.ofList
let email = map.["email"]
let company = map.["company"]
let userId = map.["uid"]
请注意,如果键不存在于映射中,像 map.["email"]
这样的索引将在运行时崩溃。如果丢失键“通常不应该发生”,这很好,但是如果你想优雅地处理这种情况,请改用 Map.tryFind
,这将 return 你 option
:
let email = map |> Map.tryFind "email"