如何修改给定索引处的列表元素
How to modify a List element at a given index
我所做的(在朋友的帮助下)创建了一个函数,该函数采用 List
、Int
作为索引,以及一个应用于元素的函数指定的索引。它与 Map
类似,但不是将函数应用于每个元素,而是仅将其应用于一个元素。
所以我的问题是:
- 这个函数是否已经存在于核心的某个地方?我们找不到它。
- 如果没有,是否有比我们已经做到的更好的方法来实现这一目标?
代码如下:
import Html exposing (text)
main =
let
m = {arr=[1,5,3], msg=""}
in
text (toString (getDisplay m 4 (\x -> x + 5)))
type alias Model =
{ arr : List (Int)
, msg : String
}
getDisplay : Model -> Int -> (Int -> Int) -> Model
getDisplay model i f =
let
m = (changeAt model.arr i f)
in
case m of
Ok val ->
{model | arr = val, msg = ""}
Err err ->
{model | arr = [], msg = err}
changeAt : List a -> Int -> (a -> a) -> Result String (List a)
changeAt l i func =
let
f j x = if j==i then func x else x
in
if i < (List.length l) && i >= 0 then
Ok(List.indexedMap f l)
else
Err "Bad index"
注意:Elm discourages indexing Lists, as they are linked lists under the hood: to retrieve the 1001th element, you have to first visit all 1000 previous elements.尽管如此,如果您想这样做,这是一种方法。
List.indexedMap
是完成您所描述的事情的好方法。
但是,由于您提到了必须访问列表中所有前面元素的缺点,如果您确实非常担心性能,那么您示例中的实际情况实际上更糟。
不管索引是否存在,你的列表实际上至少被完整遍历了两次。要求链表长度的简单行为必须遍历整个链表。查看源代码,length
is implemented in terms of a foldl
.
此外,List.indexedMap
至少遍历整个列表一次。我说,至少一次,因为除了使用 map
之外,indexedMap
的来源也 calls the length
function。如果幸运的话,length
调用会被记住(我对 Elm 内部结构还不够熟悉,不知道它是否是,因此 at least 评论)。 map
本身在调用时会遍历整个列表,这与 Haskell 不同,后者会惰性地求值,只在必要时才求值。
并且如果您使用indexedMap
,则无论您感兴趣的位置如何,都会对整个列表进行索引。也就是说,即使您想在索引零处应用函数,也会对整个列表进行索引。
如果你真的想将遍历次数减少到最低限度,你将(此时)必须实现你自己的功能并且你必须在不依赖length
或 indexedMap
.
这里是一个 changeAt
函数的例子,它避免了不必要的遍历,如果它找到了位置,它就会停止遍历列表。
changeAt : List a -> Int -> (a -> a) -> Result String (List a)
changeAt l i func =
if i < 0 then
Err "Bad Index"
else
case l of
[] ->
Err "Not found"
(x::xs) ->
if i == 0 then
Ok <| func x :: xs
else
Result.map ((::) x) <| changeAt xs (i - 1) func
它不是很漂亮,但如果你想避免不必要地遍历列表 - 多次 - 那么你可能想要使用这样的东西。
您正在寻找 the set
function for Arrays。与其使用您描述的效率低下的列表,不如使用此结构更适合您的用例。
这是您正在寻找的功能的有效实现:
changeAt : Int -> (a -> a) -> Array a -> Array a
changeAt i f array =
case get i array of
Just item ->
set i (f item) array
Nothing ->
array
另请注意,此实现中的 data structure is the last argument。
Array
在你的问题的 link 中被提及,但是这个线程中没有人明确提到这个选项。
我所做的(在朋友的帮助下)创建了一个函数,该函数采用 List
、Int
作为索引,以及一个应用于元素的函数指定的索引。它与 Map
类似,但不是将函数应用于每个元素,而是仅将其应用于一个元素。
所以我的问题是:
- 这个函数是否已经存在于核心的某个地方?我们找不到它。
- 如果没有,是否有比我们已经做到的更好的方法来实现这一目标?
代码如下:
import Html exposing (text)
main =
let
m = {arr=[1,5,3], msg=""}
in
text (toString (getDisplay m 4 (\x -> x + 5)))
type alias Model =
{ arr : List (Int)
, msg : String
}
getDisplay : Model -> Int -> (Int -> Int) -> Model
getDisplay model i f =
let
m = (changeAt model.arr i f)
in
case m of
Ok val ->
{model | arr = val, msg = ""}
Err err ->
{model | arr = [], msg = err}
changeAt : List a -> Int -> (a -> a) -> Result String (List a)
changeAt l i func =
let
f j x = if j==i then func x else x
in
if i < (List.length l) && i >= 0 then
Ok(List.indexedMap f l)
else
Err "Bad index"
注意:Elm discourages indexing Lists, as they are linked lists under the hood: to retrieve the 1001th element, you have to first visit all 1000 previous elements.尽管如此,如果您想这样做,这是一种方法。
List.indexedMap
是完成您所描述的事情的好方法。
但是,由于您提到了必须访问列表中所有前面元素的缺点,如果您确实非常担心性能,那么您示例中的实际情况实际上更糟。
不管索引是否存在,你的列表实际上至少被完整遍历了两次。要求链表长度的简单行为必须遍历整个链表。查看源代码,length
is implemented in terms of a foldl
.
此外,List.indexedMap
至少遍历整个列表一次。我说,至少一次,因为除了使用 map
之外,indexedMap
的来源也 calls the length
function。如果幸运的话,length
调用会被记住(我对 Elm 内部结构还不够熟悉,不知道它是否是,因此 at least 评论)。 map
本身在调用时会遍历整个列表,这与 Haskell 不同,后者会惰性地求值,只在必要时才求值。
并且如果您使用indexedMap
,则无论您感兴趣的位置如何,都会对整个列表进行索引。也就是说,即使您想在索引零处应用函数,也会对整个列表进行索引。
如果你真的想将遍历次数减少到最低限度,你将(此时)必须实现你自己的功能并且你必须在不依赖length
或 indexedMap
.
这里是一个 changeAt
函数的例子,它避免了不必要的遍历,如果它找到了位置,它就会停止遍历列表。
changeAt : List a -> Int -> (a -> a) -> Result String (List a)
changeAt l i func =
if i < 0 then
Err "Bad Index"
else
case l of
[] ->
Err "Not found"
(x::xs) ->
if i == 0 then
Ok <| func x :: xs
else
Result.map ((::) x) <| changeAt xs (i - 1) func
它不是很漂亮,但如果你想避免不必要地遍历列表 - 多次 - 那么你可能想要使用这样的东西。
您正在寻找 the set
function for Arrays。与其使用您描述的效率低下的列表,不如使用此结构更适合您的用例。
这是您正在寻找的功能的有效实现:
changeAt : Int -> (a -> a) -> Array a -> Array a
changeAt i f array =
case get i array of
Just item ->
set i (f item) array
Nothing ->
array
另请注意,此实现中的 data structure is the last argument。
Array
在你的问题的 link 中被提及,但是这个线程中没有人明确提到这个选项。