我所做的(在朋友的帮助下)是创建一个函数,该函数采用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不鼓励建立索引列表,因为它们是幕后的链表:要检索第1001个元素,您必须首先访问所有1000个以前的元素。但是,如果您想这样做,这是一种方法。
List.indexedMap
是完成您所描述内容的好方法。
但是,由于您提到必须访问列表中的所有先前元素的不利影响,因此,如果您确实担心性能,那么示例中的实际情况实际上会更糟。
实际上,无论索引是否存在,您的列表实际上至少要经过两次遍历。要求链接列表长度的简单动作必须遍历整个列表。签出源代码,length
以实现foldl
。
此外,List.indexedMap
至少遍历整个列表一次。我说,至少一次,因为除了使用之外,的来源indexedMap
还调用了该length
函数map
。如果幸运的话,该length
电话将被记录下来(我对Elm内部人员并不十分了解,是否知道,所以至少可以发表评论)。在map
本身穿越的时候叫,不像哈斯克尔它懒洋洋地,只有尽量评估事物所必需的完整列表。
并且,如果您使用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
它不是很漂亮,但是如果您想避免不必要地遍历列表-多次-那么您可能想要使用这样的内容。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句