F#:如何遍历字符串数组的列表(字符串[]列表)的功能方式

时间:2020-05-18 17:50:58

标签: arrays list loops f# iteration

我是F#的新手, 我有一个包含数组的列表,每个数组包含7个字符串。 我想遍历数组并稍后再做某种Array.map,

但是我的问题是我无法将单个数组发送到其他函数。

我不想使用for循环,而是专注于仅使用管道和映射的功能方式。

let stockArray =
    [[|"2012-03-30"; "32.40"; "32.41"; "32.04"; "32.26"; "31749400"; "32.26"|];
    [|"2012-03-29"; "32.06"; "32.19"; "31.81"; "32.12"; "37038500"; "32.12"|];
    [|"2012-03-28"; "32.52"; "32.70"; "32.04"; "32.19"; "41344800"; "32.19"|];
    [|"2012-03-27"; "32.65"; "32.70"; "32.40"; "32.52"; "36274900"; "32.52"|];]

let tryout =
    stockArray
    |> List.iter;;

输出抱怨List.iter:

error FS0001: Type mismatch. Expecting a
'string [] list -> 'a' but given a
'('b -> unit) -> 'b list -> unit' 
The type 'string [] list' does not match the type ''a -> unit'

尝试Array.iter时,有相同的区别:

 error FS0001: Type mismatch. Expecting a
'string [] list -> 'a' but given a
'('b -> unit) -> 'b [] -> unit' 
The type 'string [] list' does not match the type ''a -> unit'

在C#中,我会简单地使用foreach进行处理,以一次开始处理我的数组,但是在使用F#时,我真的感到很困惑。

感谢您的帮助

3 个答案:

答案 0 :(得分:1)

即使有其他注释,问题也不清楚。无论如何,我认为您终于可以从此答案中找出您的需求。

我已经以这样的方式实现了parseDate和parseFloat,我希望它可以在给定数据的任何计算机上工作,无论是哪种语言环境。您可能需要其他一些用于生产应用程序的内容。另外,InIn的计算方式可能不是您想要的。

您已经发现,

List.iter将数据转换为unit,有效地丢弃了数据。那有什么意义呢?通常将其放在管道序列中时放在最后,经常做一些涉及副作用(例如打印数据)或可变数据操作(例如用项目填充可变列表)的工作。我建议您研究“列表”,“数组”,“序列”和“选项”模块中的函数,以了解它们如何用于转换数据。

open System
open System.Globalization

let stockArray =
    [
        [| "2012-03-30"; "32.40"; "32.41"; "32.04"; "32.26"; "31749400"; "32.26" |]
        [| "2012-03-29"; "32.06"; "32.19"; "31.81"; "32.12"; "37038500"; "32.12" |]
        [| "2012-03-28"; "32.52"; "32.70"; "32.04"; "32.19"; "41344800"; "32.19" |]
        [| "2012-03-27"; "32.65"; "32.70"; "32.40"; "32.52"; "36274900"; "32.52" |]
    ]

type OutData = { TheDate: DateTime; TheInt: int }

let parseDate s = DateTime.ParseExact (s, "yyyy-MM-dd", CultureInfo.InvariantCulture)

let parseFloat s = Double.Parse (s, CultureInfo.InvariantCulture)

let myFirstMap (inArray: string[]) : OutData =
    if inArray.Length <> 7 then
        failwith "Expected array with seven strings."
    else
        let theDate = parseDate inArray.[0]
        let f2 = parseFloat inArray.[2]
        let f3 = parseFloat inArray.[3]
        let f = f2 - f3
        let theInt = int f
        { TheDate = theDate; TheInt = theInt }

let tryout =
    stockArray
    |> List.map myFirstMap

以下是myFirstMap的替代实现。我想有些人会说这更惯用,但我只是想说,您更喜欢使用什么取决于对未来可能的开发的期望。

let myFirstMap inArray =
    match inArray with
    | [| sDate; _; s2; s3; _; _; _  |] ->
        let theDate = parseDate sDate
        let f2 = parseFloat s2
        let f3 = parseFloat s3
        let f = f2 - f3
        let theInt = int f
        { TheDate = theDate; TheInt = theInt }
    | _ -> failwith "Expected array with seven strings."

答案 1 :(得分:0)

管道运算符|>用于将f x编写为x |> f

List.iter的签名是:

action: ('a -> unit) -> list: ('a list) -> unit

您给它一个操作,然后一个列表,它给您一个 void

您可以这样阅读:给List.iter做一个动作时,其类型将为

list: ('a list) -> unit

可以向其传递列表的功能。

因此,当您编写stockArray |> List.iter时,实际上是在尝试代替操作的是列表-这就是错误。因此,传递一个动作:

let tryout = List.iter (fun arr -> printfn "%A" arr) stockArray

可以改写为:

let tryout = stockArray |> List.iter (fun arr -> printfn "%A" arr) 

答案 2 :(得分:0)

但是我的问题是我无法将单个数组发送到其他函数

List.map和类似的函数使您可以精确地执行此操作-无需自己迭代列表。

例如,这将仅返回列表中每个数组的第一个元素:

stockArray
    |> List.map (fun x -> x.[0])

您可以将传递给List.map的函数替换为对一个数组进行操作并返回一些值的任何函数。