以下是串列串列:[[1,2,3],[1,2,3,4],[1,2,3]]
如何將第二個串列的每個元素增加第一個串列的長度,并將第三個串列的長度增加第一個串列 第二個串列的長度?第一個串列應保持不變。
預期輸出:[[1,2,3],[4,5,6,7],[8,9,10]]
由于第一個串列的長度為 3,因此第二個串列由 生成[1 3, 2 3, 3 3, 4 3]。
由于第一個串列 第二個串列組合的長度為 7,因此第三個串列由 生成[1 7, 2 7, 3 7]。
理想情況下,它應該適用于任意數量的串列。
到目前為止,我已經使用這個取得了輕微的成功:
scanl1 (\xs ys -> [y length xs | y <- ys]) [[1,2,3],[1,2,3,4],[1,2,3]]
輸出:[[1,2,3],[4,5,6,7],[5,6,7]]
uj5u.com熱心網友回復:
scanl1是一個好主意,但它并不完全正確,因為您不希望您的累加器是一個串列,而是一個整數。所以你真的想要scanl,不是scanl1。我將把它作為練習留給你看看如何調整你的解決方案 - 鑒于你設法用 撰寫了幾乎正確的東西scanl1,我認為一旦你擁有正確的功能,你會發現它不會太難。
在評論中,jpmariner 建議mapAccumL:: (s -> a -> (s, b)) -> s -> [a] -> (s, [b]))。這對于我們想要做的事情來說是完美的,所以讓我們看看它會是什么樣子。
import Data.Traversable (mapAccumL)
addPreviousLengths :: [[Int]] -> [[Int]]
addPreviousLengths = snd . mapAccumL go 0
where go n xs = (n length xs, map ( n) xs)
λ> addPreviousLengths [[1,2,3],[1,2,3,4],[1,2,3]]
[[1,2,3],[4,5,6,7],[8,9,10]]
mapAccumL確實是這項作業的最佳工具 - 使用它并沒有太多不必要的復雜性。但是,如果您嘗試從頭開始實作此功能,則可以嘗試 Francis King 建議的遞回方法。不過,我建議使用惰性演算法而不是尾遞回演算法:
incrLength :: [[Int]] -> [[Int]]
incrLength = go 0
where go _ [] = []
go amount (x:xs) =
map ( amount) x : go (amount length x) xs
它的作業原理與 mapAccumL 版本相同。請注意,這兩個版本都是惰性的:它們只消耗必要的輸入串列。這是尾遞回方法不具備的優勢。
λ> take 3 . incrLength $ repeat [1]
[[1],[2],[3]]
λ> take 3 . addPreviousLengths $ repeat [1]
[[1],[2],[3]]
uj5u.com熱心網友回復:
有很多方法可以解決這個問題。一個簡單的遞回是一種方法:
lst :: [[Int]]
lst = [[1,2,3],[1,2,3,4],[1,2,3]]
incrLength :: [[Int]] -> Int -> [[Int]] -> [[Int]]
incrLength [] _ result = result
incrLength (x:xs) amount result =
incrLength xs (amount length x) (result [map ( amount) x])
(編輯:在此函式中使用 (:) 更有效。請參閱下面的@amalloy 評論。然后必須反轉結果。
incrLength :: [[Int]] -> Int -> [[Int]] -> [[Int]]
incrLength [] _ result = reverse result
incrLength (x:xs) amount result =
incrLength xs (amount length x) (map ( amount) x : result)
結束編輯)
另一種方法是使用scanl. 我們length用來獲取內部串列的長度,然后使用scanl.
map length lst -- [3,4,3]
scanl ( ) 0 $ map length lst -- [0,3,7,10]
init $ scanl ( ) 0 $ map length lst -- [0,3,7]
然后我們將 lst 和累積值壓縮在一起,并將一個映射到另一個。
incrLength' :: [[Int]] -> [[Int]]
incrLength' lst =
[map ( snd y) (fst y) | y <- zip lst addlst]
where
addlst =init $scanl ( ) 0 $ map length lst
main = do
print $ incrLength lst 0 [] -- [[1,2,3],[4,5,6,7],[8,9,10]]
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/517117.html
標籤:哈斯克尔
