Skip to content

Commit 43e0284

Browse files
Add transpose and transpose' to NonEmptyArray (#228)
* Add transpose to Data.Array Implementation courtesy of Jordan Martinez. * Update CHANGELOG * Improve layout of doc comments * Add transpose and transpose' to NonEmptyArray * Add dependency on safe-coerce and implement the functions that transform 2D arrays between Array and NonEmptyArray representations to use coerce. * inline what were the two coerce2D functions * Alter the signature of transpose' so that it returns a Maybe. This is necessary in order to handle the edge case of transpose` (NonEmptyArray [ [] ]).
1 parent e5d80f3 commit 43e0284

File tree

4 files changed

+62
-0
lines changed

4 files changed

+62
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Breaking changes:
88

99
New features:
1010
- Added `transpose` to `Array` (#225 by @newlandsvalley and @JordanMartinez)
11+
- Added `transpose` and `transpose' `to `Array.NonEmpty` (#227 by @newlandsvalley and @JordanMartinez)
1112

1213
Bugfixes:
1314

bower.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"purescript-nonempty": "^7.0.0",
2323
"purescript-partial": "^4.0.0",
2424
"purescript-prelude": "^6.0.0",
25+
"purescript-safe-coerce": "^2.0.0",
2526
"purescript-st": "^6.0.0",
2627
"purescript-tailrec": "^6.0.0",
2728
"purescript-tuples": "^7.0.0",

src/Data/Array/NonEmpty.purs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ module Data.Array.NonEmpty
6464
, foldMap1
6565
, fold1
6666
, intercalate
67+
, transpose
68+
, transpose'
6769
, scanl
6870
, scanr
6971

@@ -133,6 +135,7 @@ import Data.Tuple (Tuple(..))
133135
import Data.Unfoldable (class Unfoldable)
134136
import Data.Unfoldable1 (class Unfoldable1, unfoldr1)
135137
import Partial.Unsafe (unsafePartial)
138+
import Safe.Coerce (coerce)
136139
import Unsafe.Coerce (unsafeCoerce)
137140

138141
-- | Internal - adapt an Array transform to NonEmptyArray
@@ -361,6 +364,44 @@ fold1 = F.fold1
361364
intercalate :: forall a. Semigroup a => a -> NonEmptyArray a -> a
362365
intercalate = F.intercalate
363366

367+
-- | The 'transpose' function transposes the rows and columns of its argument.
368+
-- | For example,
369+
-- |
370+
-- | ```purescript
371+
-- | transpose
372+
-- | (NonEmptyArray [ NonEmptyArray [1, 2, 3]
373+
-- | , NonEmptyArray [4, 5, 6]
374+
-- | ]) ==
375+
-- | (NonEmptyArray [ NonEmptyArray [1, 4]
376+
-- | , NonEmptyArray [2, 5]
377+
-- | , NonEmptyArray [3, 6]
378+
-- | ])
379+
-- | ```
380+
-- |
381+
-- | If some of the rows are shorter than the following rows, their elements are skipped:
382+
-- |
383+
-- | ```purescript
384+
-- | transpose
385+
-- | (NonEmptyArray [ NonEmptyArray [10, 11]
386+
-- | , NonEmptyArray [20]
387+
-- | , NonEmptyArray [30, 31, 32]
388+
-- | ]) ==
389+
-- | (NomEmptyArray [ NonEmptyArray [10, 20, 30]
390+
-- | , NonEmptyArray [11, 31]
391+
-- | , NonEmptyArray [32]
392+
-- | ])
393+
-- | ```
394+
transpose :: forall a. NonEmptyArray (NonEmptyArray a) -> NonEmptyArray (NonEmptyArray a)
395+
transpose =
396+
(coerce :: (Array (Array a)) -> (NonEmptyArray (NonEmptyArray a)))
397+
<<< A.transpose <<< coerce
398+
399+
-- | `transpose`' is identical to `transpose` other than that the inner arrays are each
400+
-- | a standard `Array` and not a `NonEmptyArray`. However, the result is wrapped in a
401+
-- | `Maybe` to cater for the case where the inner `Array` is empty and must return `Nothing`.
402+
transpose' :: forall a. NonEmptyArray (Array a) -> Maybe (NonEmptyArray (Array a))
403+
transpose' = fromArray <<< A.transpose <<< coerce
404+
364405
scanl :: forall a b. (b -> a -> b) -> b -> NonEmptyArray a -> NonEmptyArray b
365406
scanl f x = unsafeAdapt $ A.scanl f x
366407

test/Test/Data/Array/NonEmpty.purs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,25 @@ testNonEmptyArray = do
397397
log "traverse1 should work"
398398
assert $ traverse1 Just (fromArray [1, 2, 3, 4]) == NEA.fromArray [1, 2, 3, 4]
399399

400+
log "transpose swaps rows and columns for a regular two-dimension array"
401+
assert $ NEA.transpose (fromArray [ (fromArray [1,2,3]), (fromArray [4,5,6]), (fromArray [7,8,9])]) ==
402+
(fromArray [ (fromArray [1,4,7]), (fromArray [2,5,8]), (fromArray [3,6,9])])
403+
404+
log "transpose skips elements when rows don't match"
405+
assert $ NEA.transpose (fromArray [ (fromArray [10,11]), (fromArray [20]), (fromArray [30,31,32])]) ==
406+
(fromArray [ (fromArray [10,20,30]), (fromArray [11,31]), (fromArray [32])])
407+
408+
log "transpose' handles the singleton empty array"
409+
assert $ NEA.transpose' (fromArray [ [] ]) == (Nothing :: Maybe (NEA.NonEmptyArray (Array Int)))
410+
411+
log "transpose' swaps rows and columns for a regular two-dimension array"
412+
assert $ NEA.transpose' (fromArray [[1,2,3], [4,5,6], [7,8,9]]) ==
413+
(Just $ fromArray [[1,4,7], [2,5,8], [3,6,9]])
414+
415+
log "transpose' skips elements when rows don't match"
416+
assert $ NEA.transpose' (fromArray [[10,11], [20], [30,31,32]]) ==
417+
(Just $ fromArray [[10,20,30], [11,31], [32]])
418+
400419
odd :: Int -> Boolean
401420
odd n = n `mod` 2 /= zero
402421

0 commit comments

Comments
 (0)