我有一個二維串列 l,和
[l!!y!!x| x<-[0..length l-1], y<-[0..length l-1]]
將生成一個 1d 串列,其中交換行和列。
如何在沒有串列理解的情況下實作這一點(即使用地圖)?
uj5u.com熱心網友回復:
既然你想要它沒有明確的遞回,
zipWith也是一種二進制map型別(并且在其他一些語言中map實際上可以采用任意數量的引數串列)。因此,
transposed = foldr (zipWith (:)) (repeat [])
嘗試:
> transposed [[1,2,3],[11,12,13],[21,22,23,24]]
[[1,11,21],[2,12,22],[3,13,23]]
這可以簡單地組合concat :: [[a]] -> [a]以連接轉置串列。
uj5u.com熱心網友回復:
把問題分解成幾個部分。要轉置單行,您需要回傳一列,其中每行包含一個元素。阿1個XN矩陣變成為nx 1矩陣:
{- 1 2 ... n 1
2
...
n
-}
transpose [row] = map (\ x -> [x]) row
例如:transpose [[1, 2, 3]]= [[1], [2], [3]]。
\ x -> [x]也可以寫為運算子部分(: [])或pure從Applicative.
當您對外部串列(輸入行)進行模式匹配時,您將矩陣的頂行與其余行分開。矩陣的轉置是將第一行的轉置置于其余行的轉置之前。您可以垂直連接兩個矩陣(( )即將一個放在另一個之上)(可以寫成(<>)from Semigroup)或水平連接zipWith ( )(分別是zipWith (<>))(即將一個放在另一個旁邊)。轉置矩陣水平連接:
{- 1 2 ... n 1 a ... p
a b ... c 2 b ... q
....... .........
p q ... r n c ... r
-}
transpose (top : down)
= zipWith ( ) (transpose [top]) (transpose down)
例如:= 。transpose [[1, 2], [3, 4], [5, 6]][[1] [3, 5], [2] [4, 6]]
這也可以表示為zipWith (:) top (transpose down)因為我們知道我們有單個元素要添加;這跳過了一些多余的包裝作業,然后立即展開輸入行/輸出列的元素。
最后,一個沒有行的空矩陣的轉置也是空矩陣。
transpose [] = []
把這些放在一起:
transpose :: [[a]] -> [[a]]
transpose [r] = map (: []) r
transpose (r : rs) = zipWith (:) r (transpose rs)
transpose [] = []
跟進:考慮此代碼如何回應輸入為非矩形或具有無限行數或列數的邊緣情況。
作為威爾內斯的回答表明,這個遞回函式幾乎相當于一個右折,當該組合功能是通過列的預謀zipWith (:),基累加器是不確定的高度,空列repeat [],即transpose m = foldr (zipWith (:)) (repeat []) m,或ETA-減少transpose = foldr (zipWith (:)) (repeat [])。
然而,它們在邊緣情況下有所不同:當給定一個空輸入時,它會產生一個無限串列。該版本也等價于getZipList . traverse ZipList,基于traverse id :: (Traversable t, Applicative f) => t (f b) -> f (t b)一種廣義換位的觀察。
uj5u.com熱心網友回復:
我們可以使用遞回來解決這個問題:每次我們產生head串列的s,然后在尾部遞回,所以:
catTranspose :: [[a]] -> [a]
catTranspose ([]:_) = []
catTranspose xs = map head xs …
我把填寫…作為練習。它應該進行遞回呼叫,我們將每個專案映射xs到它的尾部。
如果串列是矩形的,這將起作用,對于非矩形 2d 串列,您將需要使用更安全的函式,因此不會像head空串列那樣出錯。
你也可以洗掉,例如具有明確的遞回和作業unfoldr :: (b -> Maybe (a, b)) -> b -> [a],并concat :: Foldable f => f [a] -> [a]隨后將執行遞回。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/348931.html
