我有一个函数,其中Array.iter用于在应用函数后打印嵌套数组的第4个元素(z)。我正在喂一条由' \ n'划分的长串。然后(嵌套)划分'"'。它似乎迭代到更高级别数组(y)的末尾。
let digestMDtest (x : string) =
let y = x.Split '\n' |> Array.tail
let mapMD (x : string) =
let z = x.Split '"'
printfn "%s" z.[3]
Array.iter mapMD y
我收到错误,你可以看到最后3个时间戳是我所参与的数据的一部分," 2016-04-15T15:59:00-04:00"是最后一个元素,它似乎超越了它。
2016-04-15T15:57:00-04:00
2016-04-15T15:58:00-04:00
2016-04-15T15:59:00-04:00
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at FSI_0002.mapMD@69-1(String x) in C:\OneDrive\FSMDC.barchart.fsx:line 70
at FSI_0002.digestMDtest(String x) in C:\OneDrive\FMDC.barchart.fsx:line 72
在我看来,Array.iter函数正在尝试迭代超出数组末尾的Array元素。它为什么要这样做?我只能假设Array.tail与它有关;也许Array.iter正在使用数组的原始大小而不是当前大小?
答案 0 :(得分:4)
鉴于您对输入数据的书面描述,我创建了一个这样的示例设置(如果我误解了您的描述,请告诉我!):
let data = "\"2016-04-15T15:57:00-04:00\"\n\"2016-04-15T15:58:00-04:00\"\n\"2016-04-15T15:59:00-04:00\""
假设我的数据与您的数据大致匹配,您将跳过第一个值,然后Array.iter
超过其余两个值:
"2016-04-15T15:58:00-04:00"
"2016-04-15T15:59:00-04:00"
然后在每个元素上调用此函数:
let mapMD (x : string) =
let z = x.Split '"'
printfn "%s" z.[3]
在这些字符串上调用Split
会得到如下结果:
[|"", date, ""|]
您从此数组索引元素.[3]
,但只有3个元素,因此这将在每个元素上触发IndexOutOfRangeException
。
索引元素一般来说在函数式编程中不是一个好模式,使用一种模式,你可以使意图更明确,通常更好。
举个例子,如果我在这种情况下尝试提取日期字符串,我会这样做:
let mapMD (x : string) =
match x.Split '"' with
|[|_; date; _|] -> printfn "%s" date
|_ -> raise <| FormatException("Invalid Date String Format")
您可以在这里看到,模式匹配简明扼要地描述了字符串数组的预期格式。
答案 1 :(得分:2)
IndexOutOfRange
异常与Array.iter
无关,而是与索引到另一个数组 - 特别是在第70行,表达式z.[3]
。
显然,您的行有少于四个以引号分隔的部分。
作为旁注,我建议分别使用Seq.skip
和Seq.iter
代替Array.tail
和Array.iter
。 Array.tail
调用将重新分配一个全新的数组,这可能会变得昂贵。
let digestMDtest (x : string) =
x.Split '\n'
|> Seq.skip 1
|> Seq.iter (fun (x : string) ->
let z = x.Split '"'
printfn "%s" z.[3] )