F#:返回索引在元素处的列表已更改

时间:2019-04-30 02:24:01

标签: f#

在F#中,我需要从现有列表中获取一个列表,其中特定索引处的值与原始值有所不同。我在Google上能找到的所有内容都与基于值而不是索引进行更改有关(足够公平,因为列表实际上没有“索引”的概念,但是我敢打赌每个人都知道我的意思)。

这显然很容易编写代码。目前,我有:

// Replace element at index with newElement in seq. Does nothing if index is outside seq.
let updateElement index newElement seq =
    let rec updateElementHelper seq count result =
        match seq with
        | [] -> result |> List.rev
        | head::tail ->
            if count = index then 
                updateElementHelper [] (count + 1) (newElement::result)@tail
            else
                updateElementHelper tail (count + 1) (head::result)
    updateElementHelper seq 0 []

这似乎很好用,但是还有比这更原生的方法吗?

(F#新手-或者说,经过很长的休息后重新播放,并且第一次都没有那么远。)

2 个答案:

答案 0 :(得分:2)

最简单的实现方法可能是使用List.mapi函数-它调用为列表的每个元素提供的函数并为您提供索引,因此您可以返回原始元素或新的元素,具体取决于索引:

let updateElement index element list = 
  list |> List.mapi (fun i v -> if i = index then element else v)

updateElement 4 40 [ 0 .. 9 ]

正如@Jarak所指出的那样,如果您需要经常执行此操作,那么可能值得考虑的是,在不依赖索引的情况下,是否还有其他更实用的方法可以解决您的问题-这样做不是很容易在功能代码中要做的典型事情。

答案 1 :(得分:1)

我假设您不想让列表可变。如果您这样做了,那么您可以索引列表并更新值,例如mylist.[index] <- newValue

我现在要说的是,对列表使用任何其他访问方式(除了典型的“ head + tail->尾部递归”样式)的任何操作都是一个强烈的信号,表明列表不是正确的数据结构您的操作。参见例如Juliet's answer here.通常,如果要按索引对线性数据结构进行操作,则最好的选择是数组。

如果您仍想使用列表,我想到的最简单的方法就是:

let newList = oldList.[..index - 1] @ (newValue :: oldList.[index + 1..])

(我可能会略微降低索引)

但是,这可能会导致性能很差。我认为可以很合理地说许多F#-er会调用@或List切片代码气味的任何用法。作为对小列表的很少操作,可能不错,但是如果经常使用或在大列表上使用它,那么现在正是开始考虑列表是否真的适合您的任务的最佳时机。