2016-04-11 7 views
0

私は(友人からの助けを借りて)List,Intを要素に適用する関数を作成します指定されたインデックスMapと似ていますが、すべての要素に関数を適用するのではなく、1つの要素にのみ適用します。指定されたインデックスでList要素を変更する方法

は、だから私の質問は以下のとおりです。

  • この機能は、すでにどこか心に存在していますか?私たちはそれを見つけることができませんでした。
  • そうでない場合は、これを達成するより良い方法がありますか?

ここでは、コードです:あなたはそれをやってみたかった場合はそれにもかかわらず、これは一つの方法です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.

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" 

NOTE。

答えて

1

List.indexedMapは、あなたが説明していることを行うのに適した方法です。

しかし、リスト内の先行するすべての要素を参照しなければならないという欠点があるため、実際にパフォーマンスが心配されている場合は、実際の例は実際には少し悪化します。

インデックスが存在するかどうかにかかわらず、リストは実際には少なくとも2回完全にトラバースされます。リンクされたリストの長さを求める単純な行為は、リスト全体を走査しなければならない。ソースコードlength is implemented in terms of a foldlをチェックしてください。

さらに、List.indexedMapは、リスト全体を少なくとも1回通過します。少なくともと言いますと、に加えて、indexedMapのソースもcalls the length functionであるので、少なくとも1回はです。私たちが運が良ければ、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 

それはひどくきれいではありませんが、あなたは、リストを歩いて不必要に回避したい場合 - 複数回 - そして、あなたはこのような何かに行きたいかもしれません。

0

あなたは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がこのリンクに記載されていますが、このスレッドの誰もこのオプションを明示していませんでした。

関連する問題