オブジェクトのリストとこのリストのインデックスのリストが与えられている場合、このリストのすべてのオブジェクトをリストからのインデックスで簡単に変更できます指標の異なる値への変換?Haskell:リストからすべてのインデックスをある値に変更する
など。私はそこに期待して、このようないくつかの関数fを存在だということ
f 0 [4,2,5] [6,5,8,4,3,6,2,7]
だろう。これは、リスト内包表記を用いて達成することができる
[6,5,0,4,0,0,2,7]
オブジェクトのリストとこのリストのインデックスのリストが与えられている場合、このリストのすべてのオブジェクトをリストからのインデックスで簡単に変更できます指標の異なる値への変換?Haskell:リストからすべてのインデックスをある値に変更する
など。私はそこに期待して、このようないくつかの関数fを存在だということ
f 0 [4,2,5] [6,5,8,4,3,6,2,7]
だろう。これは、リスト内包表記を用いて達成することができる
[6,5,0,4,0,0,2,7]
出力:
f :: (Eq i, Num i, Enum i) => a -> [i] -> [a] -> [a]
f repl indices values = [if i `elem` indices then repl else v | (i, v) <- zip [0..] values]
ことではありません最も効率的な方法へしかし、特にインデックスのリストが長い場合はそれを行う。あなたは代わりに配列を試してみることができます。
単一の値を置き換えるためにヘルパー関数を定義し、それを使用してリストを折りたたむことができます。ここで
import Control.Lens
f :: a -> [Int] -> [a] -> [a]
f x is = elements (`elem` is) .~ x
がbase
以外の任意の依存関係を持っていない効率的なバージョンである:ここで
replaceAll :: a -> [Int] -> [a] -> [a]
replaceAll repVal indices values = foldl (replaceValue repVal) values indices
where replaceValue val vals index = (take index vals) ++ [val] ++ (drop (index + 1) vals)
はlens
を使用しています美しいバージョンです。基本的には、インデックスリストをソートしてから削除します。そうすれば、すべての置換のためにリスト全体をスキャンする必要はありません。
import Data.List
f :: a -> [Int] -> [a] -> [a]
f x is xs = snd $ mapAccumR go is' (zip xs [1..])
where
is' = map head . group . sort $ is
go [] (y,_) = ([],y)
go (i:is) (y,j) = if i == j then (is,x) else (i:is,y)
インデックスを最初にソートします。次に、2つのリストを並べてトラバースすることができます。
{-# LANGUAGE ScopedTypeVariables #-}
import Prelude (Eq, Enum, Num, Ord, snd, (==), (<$>))
import Data.List (head, group, sort, zip)
f :: forall a. (Eq a, Enum a, Num a, Ord a) => a -> [a] -> [a] -> [a]
f replacement indices values =
go (head <$> group (sort indices)) (zip [0..] values)
where
go :: [a] -> [(a, a)] -> [a]
go [] vs = snd <$> vs
go _ [] = []
go (i:is) ((i', v):vs) | i == i' = replacement : go is vs
go is (v:vs) = snd v : go is vs
ソートは、インデックスリストの長さに余分なログ要因を招きますが、残りは直線的です。
私は、試行や事前の努力がないため、この質問をトピックとして閉じるよう投票しています。 –