根据 F# 中的条件重新格式化列表
Reformatting list based on a condition in F#
我是函数式编程的新手,正在使用 F# 开发一个项目。
我 运行 遇到了一个问题:我有一个 string list list
类型的列表,我需要根据每个 string list
的中间元素构建单独的列表。例如:
[["1";"b";"2"];["2";"a";"0"];["3";"b";"4"];["3";"a";"5"]]
将分成 2 个类似于以下的列表:
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" 的条件时遇到了问题。
如有任何帮助,我们将不胜感激
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]]
您正在尝试按中间元素拆分列表。当您的列表没有 3 个元素时,预期的行为是什么?
在 Functional_S 提供的答案中,您会看到
中 [x;y;z]
下的波浪线
let a = [for [x;y;z] in myList do if y="a" then yield [x;z]]
编译器说 "Incomplete pattern matches"。与其现在添加额外的检查来处理空列表、长度为 2 的列表等,不如考虑更改数据类型的设计。如果您的数据始终包含 3 个元素,则使用恰好包含 3 个元素的数据结构。元组在这里是一个明显的选择,或者使用记录。
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")])]
另一种选择是:
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)
我发现当您使用您的数据类型尽可能接近地为您的域建模时,F# 确实处于最佳性能。在像 Matlab 这样的语言中,向量和矩阵是你的头等大事,你会把所有东西都放在列表中。但在 F# 中,定义数据类型的成本非常低(就键入工作量而言)- 一旦您这样做了,编译器就是您最好的朋友,它会提醒您代码未涵盖的可能极端情况。
鉴于此:我看到您所有的中间元素都是字符串,而 left/right 元素是整数。也许您的域更适合此记录?
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)
这会给你:
val splitByMiddle : (string * R list) list =
[("b", [{Left = 1;
Middle = "b";
Right = 2;}; {Left = 3;
Middle = "b";
Right = 4;}]); ("a", [{Left = 2;
Middle = "a";
Right = 0;}; {Left = 3;
Middle = "a";
Right = 5;}])]
我是函数式编程的新手,正在使用 F# 开发一个项目。
我 运行 遇到了一个问题:我有一个 string list list
类型的列表,我需要根据每个 string list
的中间元素构建单独的列表。例如:
[["1";"b";"2"];["2";"a";"0"];["3";"b";"4"];["3";"a";"5"]]
将分成 2 个类似于以下的列表:
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" 的条件时遇到了问题。
如有任何帮助,我们将不胜感激
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]]
您正在尝试按中间元素拆分列表。当您的列表没有 3 个元素时,预期的行为是什么?
在 Functional_S 提供的答案中,您会看到
中[x;y;z]
下的波浪线
let a = [for [x;y;z] in myList do if y="a" then yield [x;z]]
编译器说 "Incomplete pattern matches"。与其现在添加额外的检查来处理空列表、长度为 2 的列表等,不如考虑更改数据类型的设计。如果您的数据始终包含 3 个元素,则使用恰好包含 3 个元素的数据结构。元组在这里是一个明显的选择,或者使用记录。
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")])]
另一种选择是:
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)
我发现当您使用您的数据类型尽可能接近地为您的域建模时,F# 确实处于最佳性能。在像 Matlab 这样的语言中,向量和矩阵是你的头等大事,你会把所有东西都放在列表中。但在 F# 中,定义数据类型的成本非常低(就键入工作量而言)- 一旦您这样做了,编译器就是您最好的朋友,它会提醒您代码未涵盖的可能极端情况。
鉴于此:我看到您所有的中间元素都是字符串,而 left/right 元素是整数。也许您的域更适合此记录?
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)
这会给你:
val splitByMiddle : (string * R list) list =
[("b", [{Left = 1;
Middle = "b";
Right = 2;}; {Left = 3;
Middle = "b";
Right = 4;}]); ("a", [{Left = 2;
Middle = "a";
Right = 0;}; {Left = 3;
Middle = "a";
Right = 5;}])]