【问题标题】:Is it possible to use immutable collections in this case?在这种情况下是否可以使用不可变集合?
【发布时间】:2019-12-19 15:16:47
【问题描述】:

我已将代码从 python 翻译成 F#,但我希望使用更惯用的语法。 我认为有两大障碍

  • 性能不佳(考虑n很大)
  • 抽象不够强大

我拥有的当前(工作)代码是

let valuefolded =
    System.Collections.Generic.List(
        [0..( (n - (offset % input.Length) - 1) / input.Length)]
        |> List.fold
            (fun acc _ -> List.append acc input)
            (input
            |> List.skip (offset % input.Length)))
for repeat in [0..99] do  
    let mutable acc = 0
    for i in ([0..(n-1)] |> List.rev) do
        valuefolded.[i] <- Math.Abs(acc + valuefolded.[i]) % 10
        acc <- valuefolded.[i]

(在我的笔记本电脑上使用实际数据大约需要一分钟)

现在有两个可变的我希望使其不可变,如果可能并且有意义的话。

  1. mutable acc(已完成,见下文)
  2. System.Collections.Generic.List 包装器

【问题讨论】:

  • 通过使集合不可变,您将获得什么好处?
  • 嗯,它必须对你的应用程序“有意义”。只有你可以决定。
  • 好的。因此,您已将代码更改为您更喜欢的新版本,而不会影响性能。您的具体问题是什么?
  • 在不影响性能的情况下可能无法做到这一点。你愿意为了更好的风格而牺牲性能吗?
  • 要修改不可变集合,您必须将集合复制到新集合,同时修改途中的数据。这总是需要一些时间。某些集合(例如树)允许修剪(这比复制整个集合要快),但总会对性能造成某种影响。

标签: f# immutability immutable-collections


【解决方案1】:

看起来您使用Generic.List 只是为了拥有一个可以按索引访问的集合。您可以改用内置的Array。 这是代码

let valuefolded =        
        [0..( (n - (offset % input.Length) - 1) / input.Length)]
        |> List.fold
            (fun acc _ -> List.append acc input)
            (input
            |> List.skip (offset % input.Length))
        |> Array.ofList

另外,我鼓励您自己检查,但我对以下参数的观察

let offset = 1
    let input = [1..10000000]
    let n = 3

表明它比原始版本执行得更快。

【讨论】:

  • @Giulio - 你几乎不想通过索引访问不可变列表,因为与数组的 O(1) 相比,它是 O(n)。
猜你喜欢
  • 2015-06-23
  • 2021-07-10
  • 1970-01-01
  • 1970-01-01
  • 2018-05-05
  • 1970-01-01
  • 2022-11-14
  • 2014-07-07
  • 2015-10-30
相关资源
最近更新 更多