Skip to content

Add transpose to Data.Array #226

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Notable changes to this project are documented in this file. The format is based
Breaking changes:

New features:
- Added `transpose` to `Array` (#225 by @newlandsvalley and @JordanMartinez)

Bugfixes:

Expand Down
41 changes: 41 additions & 0 deletions src/Data/Array.purs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ module Data.Array
, foldMap
, fold
, intercalate
, transpose
, scanl
, scanr

Expand Down Expand Up @@ -781,6 +782,46 @@ fold = F.fold
intercalate :: forall a. Monoid a => a -> Array a -> a
intercalate = F.intercalate

-- | The 'transpose' function transposes the rows and columns of its argument.
-- | For example,
-- |
-- | ```purescript
-- | transpose
-- | [ [1, 2, 3]
-- | , [4, 5, 6]
-- | ] ==
-- | [ [1, 4]
-- | , [2, 5]
-- | , [3, 6]
-- | ]
-- | ```
-- |
-- | If some of the rows are shorter than the following rows, their elements are skipped:
-- |
-- | ```purescript
-- | transpose
-- | [ [10, 11]
-- | , [20]
-- | , [30, 31, 32]
-- | ] ==
-- | [ [10, 20, 30]
-- | , [11, 31]
-- | , [32]
-- | ]
-- | ```
transpose :: forall a. Array (Array a) -> Array (Array a)
transpose xs = go 0 []
where
go :: Int -> Array (Array a) -> Array (Array a)
go idx allArrays = case buildNext idx of
Nothing -> allArrays
Just next -> go (idx + 1) (snoc allArrays next)

buildNext :: Int -> Maybe (Array a)
buildNext idx = do
xs # flip foldl Nothing \acc nextArr -> do
maybe acc (\el -> Just $ maybe [el] (flip snoc el) acc) $ index nextArr idx

-- | Fold a data structure from the left, keeping all intermediate results
-- | instead of only the final result. Note that the initial value does not
-- | appear in the result (unlike Haskell's `Prelude.scanl`).
Expand Down
14 changes: 14 additions & 0 deletions test/Test/Data/Array.purs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,20 @@ testArray = do
assert $ A.modifyAtIndices [0, 2, 8] not [true, true, true, true] ==
[false, true, false, true]

log "transpose swaps rows and columns for a regular two-dimension array"
assert $ A.transpose [[1,2,3], [4,5,6], [7,8,9]] ==
[[1,4,7], [2,5,8], [3,6,9]]

log "transpose skips elements when rows don't match"
assert $ A.transpose [[10,11], [20], [30,31,32]] ==
[[10,20,30], [11,31], [32]]

log "transpose [] == []"
assert $ A.transpose [] == ([] :: Array (Array Int))

log "transpose (singleton []) == []"
assert $ A.transpose (A.singleton []) == ([] :: Array (Array Int))

log "scanl should return an array that stores the accumulated value at each step"
assert $ A.scanl (+) 0 [1,2,3] == [1, 3, 6]
assert $ A.scanl (-) 10 [1,2,3] == [9, 7, 4]
Expand Down