如果給出了列表中的對象列表和列表中的某些索引的另一個列表,是否有一種簡單方法可以通過列表中的索引更改此列表中的每個對象的指數到不同的價值?Haskell:將列表中的所有索引更改爲某個值
E.g.我希望存在一些函數f,使得
f 0 [4,2,5] [6,5,8,4,3,6,2,7]
將輸出
[6,5,0,4,0,0,2,7]
如果給出了列表中的對象列表和列表中的某些索引的另一個列表,是否有一種簡單方法可以通過列表中的索引更改此列表中的每個對象的指數到不同的價值?Haskell:將列表中的所有索引更改爲某個值
E.g.我希望存在一些函數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]
這不是最有效的方法不過,特別是如果指數清單很長的話。你可以嘗試使用數組。
您可以定義一個輔助函數來替換單個值,然後使用它來摺疊列表。
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 Control.Lens
f :: a -> [Int] -> [a] -> [a]
f x is = elements (`elem` is) .~ x
這裏是沒有比其他base
任何依賴一個有效的版本。基本上,我們從排序(並從索引列表中刪除重複項)開始。這樣,我們無需爲每個替代品掃描整個列表。
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)
排序指數的第一。然後你可以一前一後地遍歷這兩個列表。
{-# 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
分選招致在索引列表的長度額外日誌因子,但其餘的是線性的。
我投票結束這個問題作爲題外話,因爲沒有嘗試或事先的努力。 –