在 F# 中,有没有办法同时扫描多个数组并从其中一个数组访问前一个元素?

  • 本文关键字:一个 数组 有没有 访问 元素 扫描 f#
  • 更新时间 :
  • 英文 :


我正在尝试复制以下python代码:

a = (list1 != 0) & (list3.shift() < list2) & (list3 >= list2)

所以我需要一个函数来执行类似于此伪代码的操作:

(list1, list2, list3)
|||> Array.?? (fun l1, l2, l3, l3previous -> l1 <> 0 && l3previous < l2 && l3 >= l2)

这并不存在,所以我的问题是我如何组合现有的 Array 函数来使其知道速度很重要,因为它必须实时扫描大量数据。 (奖励:我需要输出为真的索引列表(

我想我可以用zip做一个传递,构建元组,然后做一个映射来处理结果,但这肯定不会很快,有没有更快的方法可以做到这一点? 有超过一百万行,这将为每行分配一个元组, 等。

实际上,您可以在 F# 中和 Python 中一样比较列表:

let list1 = [1;2;3]
let list2 = [4;5]
let a = list1 < list2  // true

我不确定.shift()做什么(我的本地 Python 3.7.0 声称这不是一个东西(,但从你的 F# 伪代码来看,我想它应该删除第一个元素吗?如果是这样,也可以在 F# 中轻松执行此操作:

list2.Tail // Note: this will crash if the list is empty

我想不通的一件事是list1 != 0.通过玩 Python,我已经确认它不会将列表的所有元素与零进行比较,也不会检查列表是否有单个元素为零,也不会检查长度。据我所知,它总是将列表与数字 0 进行比较,我想这在动态类型上下文中是有意义的,但在 F# 中,这总是false,所以我们可以删除它。

但是,从 F# 伪代码来看,如果list1的所有元素都是非零,则看起来list != 0应该是真的。如果是这样,可以在 F# 中通过更多的仪式来完成:

list1 |> List.forall ((<>) 0)

因此,将它们组合在一起,F# 等效项(带有上述警告(将是:

let a = (list1 |> List.forall ((<>) 0)) && list3.Tail < list2 && list3 >= list2

这将具有与 Python 代码完全相同的内存和计算复杂性。也就是说,它将遍历list1一次,它将并行遍历list3list2,但两次(一次用于<比较,一次用于>=(,并且不会分配任何中间列表。

现有数组函数的组合不会像专用函数那样快,所以如果速度比可读性更重要,正如你似乎建议的那样,这样的东西应该是可取的:

let f (l1 : int array) (l2 : int array) (l3 : int array) = 
let rec loop i l3prev = 
if i >= Array.length l1 then 
true
else if l1.[i] <> 0 && l3prev < l2.[i] && l3.[i] >= l2.[i] then 
loop (i + 1) l3.[i]
else
false
loop 0 0

这假设数组的长度相等,但如果它们不是,你只需要在第一个if条件中添加边界检查。

最新更新