From fe77dcb34ed5ec86a992569aa2aa28a1a8540c71 Mon Sep 17 00:00:00 2001 From: Qusai Al Shidi Date: Fri, 20 Aug 2021 13:16:31 -0400 Subject: [PATCH] Add transpose. This is different from interleave as it returns an iterable of iterables as opposed to a single iterable. This has [precedent](https://hackage.haskell.org/package/base-4.15.0.0/docs/Data-List.html#v:transpose) in Haskell. --- toolz/itertoolz.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/toolz/itertoolz.py b/toolz/itertoolz.py index b8165162..fa7a552a 100644 --- a/toolz/itertoolz.py +++ b/toolz/itertoolz.py @@ -14,7 +14,8 @@ 'first', 'second', 'nth', 'last', 'get', 'concat', 'concatv', 'mapcat', 'cons', 'interpose', 'frequencies', 'reduceby', 'iterate', 'sliding_window', 'partition', 'partition_all', 'count', 'pluck', - 'join', 'tail', 'diff', 'topk', 'peek', 'peekn', 'random_sample') + 'join', 'tail', 'diff', 'topk', 'peek', 'peekn', 'random_sample', + 'transpose') def remove(predicate, seq): @@ -1054,3 +1055,29 @@ def random_sample(prob, seq, random_state=None): if not hasattr(random_state, 'random'): random_state = Random(random_state) return filter(lambda _: random_state.random() < prob, seq) + + +def transpose(iter_of_iters, inner_type=None, fillvalue=None): + """Transpose an interable of iterables by switching the rows and columns. + + Returns a generator that transpose an iterable of iterables. If the inner + iterable is of shorter length the missing values will be *fillvalue*. + If *inner_type* is defined the inner iterable will be made into its type. + + >>> matrix = [[1, 2, 3], [4, 5, 6]] + >>> list(transpose(matrix)) + [(1, 4), (2, 5), (3, 6)] + >>> list(transpose(matrix, inner_type=list)) + [[1, 4], [2, 5], [3, 6]] + >>> jagged_matrix = [[1, 2], [3]] + >>> list(transpose(jagged_matrix)) + [(1,3), (2, None)] + >>> database = (('Ahmed', 21), ('Sarah', 42)) + >>> tuple(transpose(database)) + (('Ahmed', 'Sarah'), (21, 42)) + """ + if inner_type: + return map(inner_type, zip_longest(*iter_of_iters, + fillvalue=fillvalue)) + else: + return zip_longest(*iter_of_iters, fillvalue=fillvalue)