2014-02-26 205 views
1

我對Haskell相當陌生,試圖弄清楚如何編寫一個函數來完成這項工作,並且在梳理Google幾個小時後我不知所措怎麼做。Haskell list:替換列表中的元素

鑑於以下兩個Haskell中的列表

[(500,False),(400,False),(952,True),(5,False),(42,False)] 
[0,2,3] 

我會如何改變首先列出的布爾在第二列表給出的一個值爲true爲

[(500,True),(400,False),(952,True),(5,True),(42,False)] 
輸出時,每個位置
+1

以s開頭忽略功能。你認爲應該是什麼? – Abizern

+0

我的第一步是將'[0,2,3]'變成'[True,False,True,True,False,False,....]',然後你可以用另一個列表和一個適當的功能。 – Ingo

回答

4

這就是我要做的事情(假設要替換的索引列表已排序)。

首先,我們在索引列表旁邊添加一個索引列表以替換原始列表。 然後,我們遞減列表,當我們碰到下一個索引來替換時,我們在所有三個列表的尾部替換布爾值和遞歸。如果這不是 的索引,則替換我們遞歸的整個替換索引列表和其他兩個列表的尾部。

setTrue :: [Int] -> [(a, Bool)] -> [(a, Bool)] 
setTrue is xs = go is xs [0..] -- "Index" the list with a list starting at 0. 
    where 
    go [] xs _ = xs -- If we're out of indexes to replace return remaining list. 
    go _ [] _ = [] -- If we run out of list return the empty list. 
    go [email protected](i:is) (x:xs) (cur:cs) 
     | i == cur = (fst x, True) : go is xs cs -- At the next index to replace. 
     | otherwise = x : go indexes xs cs -- Otherwise, keep the current element. 
2

這是基本相同,安德魯的方法,但它並沒有使用額外的索引列表,並且是傳統map多一點點啓發。請注意,與map不同,所提供的功能必須是a -> a,不能是a -> b

restrictedMap :: (a -> a) -> [Int] -> [a] -> [a] 
restrictedMap f is xs = go f is xs 0 
    where 
    go f [] xs _ = xs 
    go f _ [] _ = [] 
    go f [email protected](i:is) (x:xs) n 
     | i == n = f x : go f is xs (n+1) 
     | otherwise = x : go f ind xs (n+1) 

setTrue = restrictedMap (\(x,_) -> (x, True)) 
1

從描述中直接轉換將是:

setIndexTrue f a = [(x, p || i `elem` f) | (i, (x,p)) <- zip [0..] a] 
1

或者用夢幻般的lens庫:

setTrue :: [(a,Bool)] -> Int -> [(a,Bool)] 
setTrue xs i = xs & ix i . _2 .~ True 

setTrues :: [(a,Bool)] -> [Int] -> [(a,Bool)] 
setTrues = foldl setTrue 
0

因爲我會用這種方法未列出:

setTrue spots values = let 
    pattern n = replicate n False ++ [True] ++ Repeat False 
    toSet = foldl1 (zipWith (||)) $ map pattern spots 
    in zipWith (\s (v,o) -> (v, o || s)) toSet values