我是函数式编程的新手,正在研究F#中的项目。
我遇到了一个问题:我有一个string list list
类型的列表,我需要根据每个string list
的中间元素构建单独的列表。例如:
[["1";"b";"2"];["2";"a";"0"];["3";"b";"4"];["3";"a";"5"]]
将分为两个类似于以下内容的列表:
let a = [["2";"0"];["3";"5"]]
let b = [["1";"2"];["3";"4"]]
我尝试使用let a = [for [x;y;z] in myList do yield [x;z]]
但是在添加y =“b”的条件时遇到了问题。
非常感谢任何帮助
答案 0 :(得分:2)
let myList = [["1";"b";"2"];["2";"a";"0"];["3";"b";"4"];["3";"a";"5"]]
let a = [for [x;y;z] in myList do if y="a" then yield [x;z]]
let b = [for [x;y;z] in myList do if y="b" then yield [x;z]]
答案 1 :(得分:1)
您正尝试按其中间元素拆分列表。当您的列表没有3个元素时,预期的行为是什么?
在Functional_S提供的答案中,您会看到<{1}}下的摇摆线
[x;y;z]
编译器说“不完整模式匹配”。现在考虑更改数据类型的设计,而不是现在添加额外的检查来处理空列表,长度为2的列表等。如果您的数据始终包含3个元素,则使用具有3个元素的数据结构。元组在这里是一个明显的选择,或使用记录。
let a = [for [x;y;z] in myList do if y="a" then yield [x;z]]
如果你在互动中执行,你会得到:
let myList = [ ("1","b","2"); ("2","a","0"); ("3","b","4"); ("3","a","5") ]
let splitByMiddle =
myList
|> List.groupBy (fun (_, middle, _) -> middle)
|> List.map (fun (middle, elems) -> middle, elems |> List.map (fun (l, _, r) -> l, r))
另一种选择是:
val splitByMiddle : (string * (string * string) list) list =
[("b", [("1", "2"); ("3", "4")]); ("a", [("2", "0"); ("3", "5")])]
我发现当您使用数据类型尽可能地模拟域时,F#确实处于最佳性能。在像Matlab这样的语言中,矢量和matrics是你的头号工作马,你可以将所有内容放入列表中。但是在F#中,定义数据类型的成本非常低(在打字工作方面) - 一旦你这样做了,编译器就是你最好的朋友,提醒你代码没有覆盖的可能的极端情况。
从那个角度来看:我看到你所有的中间元素都是字符串,而左/右元素是整数。也许您的域名更好地通过此记录建模?
let splitByMiddle =
myList
|> List.map (fun (l, middle, r) -> middle, (l, r))
|> List.groupBy fst
|> List.map (fun (middle, elems) -> middle, elems |> List.map snd)
这会给你:
type R =
{
Left: int
Right: int
Middle: string
}
let create (l, m, r) = { Left = l; Right = r; Middle = m}
let myList = [ create(1,"b",2); create(2,"a",0); create(3,"b",4); create(3,"a",5) ]
let splitByMiddle =
myList
|> List.groupBy (fun r -> r.Middle)