Re: Cycling through iterables diagonally
On Friday, February 26, 2016 at 8:44:38 AM UTC+1, Pablo Lucena wrote: > Hello, > > I am trying to accomplish the following: > > Say I have a group of 4 lists as follows: > > l1 = ['a1', 'a2', 'a3', 'a4'] > l2 = ['b1', 'b2', 'b3', 'b4'] > l3 = ['c1', 'c2', 'c3', 'c4'] > l4 = ['d1', 'd2', 'd3', 'd4'] > > I would like to cycle through these lists "diagonally" in groups of > len(list) (in this example, each list has 4 items). > > cycle1: a1, b2, b3, b4 > cycle2: a2, b3, c4, d1 > cycle3: a3, b4, c1, d2 > cycle4: a4, b1, c2, d3 > > The way I thought about doing this is as follows: > > from collections import deque > from itertools import cycle > > l1 = deque(['a1', 'a2', 'a3', 'a4']) > l2 = deque(['b1', 'b2', 'b3', 'b4']) > l3 = deque(['c1', 'c2', 'c3', 'c4']) > l4 = deque(['d1', 'd2', 'd3', 'd4']) > > l1.rotate(-0) > l2.rotate(-1) > l3.rotate(-2) > l4.rotate(-3) > > groups = cycle([l1, l2, l3, l4]) > > In [115]: for group in groups: >.: if not group: >.: break >.: print(group.popleft()) >.: > a1 > b2 > c3 > d4 > a2 > b3 > c4 > d1 > a3 > b4 > c1 > d2 > a4 > b1 > c2 > d3 > > Prior to this I was mucking around with index counting while looping, and > popping lists out of a deque, popping an item out of the list, and > appending the list back into the deque during each iteration. > > Is there a better/cleaner way to do this? I was hoping for some cool > itertools logic =) > > Thanks! > > > -- > *Pablo* Hello Pablo, If you don't mind using third-party packages you could this quite straighforward with numpy: (Python 2.7) import numpy as np a = np.array([ ('a1', 'a2', 'a3', 'a4'), ('b1', 'b2', 'b3', 'b4'), ('c1', 'c2', 'c3', 'c4'), ('d1', 'd2', 'd3', 'd4')], dtype=str) nrows, ncols = a.shape for i in range(ncols): print np.diag(np.roll(a, -i, axis=1)) This prints: ['a1' 'b2' 'c3' 'd4'] ['a2' 'b3' 'c4' 'd1'] ['a3' 'b4' 'c1' 'd2'] ['a4' 'b1' 'c2' 'd3'] -- https://mail.python.org/mailman/listinfo/python-list
Re: Cycling through iterables diagonally
On 26/02/2016 09:59, Peter Otten wrote: Pablo Lucena wrote: Say I have a group of 4 lists as follows: l1 = ['a1', 'a2', 'a3', 'a4'] l2 = ['b1', 'b2', 'b3', 'b4'] l3 = ['c1', 'c2', 'c3', 'c4'] l4 = ['d1', 'd2', 'd3', 'd4'] I would like to cycle through these lists "diagonally" in groups of len(list) (in this example, each list has 4 items). Prior to this I was mucking around with index counting while looping, and popping lists out of a deque, popping an item out of the list, and appending the list back into the deque during each iteration. Is there a better/cleaner way to do this? I was hoping for some cool itertools logic =) I have a weak spot for the itertools myself, but I think in terms of clarity it is hard to beat the conventional def diagonals(a): N = len(a) for i in range(N): for k in range(N): yield a[k][(k+i)%N] print(list(diagonals([l1, l2, l3, l4]))) Of course that's as uncool as it can get ;) It might be uncool, but at least I can read it, unlike the earlier Jussi Piitulainen answer that made my head spin :) -- My fellow Pythonistas, ask not what our language can do for you, ask what you can do for our language. Mark Lawrence -- https://mail.python.org/mailman/listinfo/python-list
Re: Cycling through iterables diagonally
Pablo Lucena wrote: > Say I have a group of 4 lists as follows: > > l1 = ['a1', 'a2', 'a3', 'a4'] > l2 = ['b1', 'b2', 'b3', 'b4'] > l3 = ['c1', 'c2', 'c3', 'c4'] > l4 = ['d1', 'd2', 'd3', 'd4'] > > I would like to cycle through these lists "diagonally" in groups of > len(list) (in this example, each list has 4 items). > Prior to this I was mucking around with index counting while looping, and > popping lists out of a deque, popping an item out of the list, and > appending the list back into the deque during each iteration. > > Is there a better/cleaner way to do this? I was hoping for some cool > itertools logic =) I have a weak spot for the itertools myself, but I think in terms of clarity it is hard to beat the conventional def diagonals(a): N = len(a) for i in range(N): for k in range(N): yield a[k][(k+i)%N] print(list(diagonals([l1, l2, l3, l4]))) Of course that's as uncool as it can get ;) -- https://mail.python.org/mailman/listinfo/python-list
Re: Cycling through iterables diagonally
Pablo Lucena writes: > Hello, > > I am trying to accomplish the following: > > Say I have a group of 4 lists as follows: > > l1 = ['a1', 'a2', 'a3', 'a4'] > l2 = ['b1', 'b2', 'b3', 'b4'] > l3 = ['c1', 'c2', 'c3', 'c4'] > l4 = ['d1', 'd2', 'd3', 'd4'] > > I would like to cycle through these lists "diagonally" in groups of > len(list) (in this example, each list has 4 items). > > cycle1: a1, b2, b3, b4 > cycle2: a2, b3, c4, d1 > cycle3: a3, b4, c1, d2 > cycle4: a4, b1, c2, d3 First line should be a1, b2, c3, d4, right? > The way I thought about doing this is as follows: > > from collections import deque > from itertools import cycle [...] > Prior to this I was mucking around with index counting while looping, > and popping lists out of a deque, popping an item out of the list, and > appending the list back into the deque during each iteration. > > Is there a better/cleaner way to do this? I was hoping for some cool > itertools logic =) Here's a combination of itertools (chaining of slices for the rotations) and builtin machinery (argument spreading, a generator expression, zip, enumerate) that seems to have the desired effect. from itertools import chain, islice l1 = ['a1', 'a2', 'a3', 'a4'] l2 = ['b1', 'b2', 'b3', 'b4'] l3 = ['c1', 'c2', 'c3', 'c4'] l4 = ['d1', 'd2', 'd3', 'd4'] n = 4 chainfrom = chain.from_iterable print(*chainfrom(zip(*(chain(islice(m, k, n), islice(m, 0, k)) for k, m in enumerate([l1, l2, l3, l4]) # prints: a1 b2 c3 d4 a2 b3 c4 d1 a3 b4 c1 d2 a4 b1 c2 d3 -- https://mail.python.org/mailman/listinfo/python-list
Cycling through iterables diagonally
Hello, I am trying to accomplish the following: Say I have a group of 4 lists as follows: l1 = ['a1', 'a2', 'a3', 'a4'] l2 = ['b1', 'b2', 'b3', 'b4'] l3 = ['c1', 'c2', 'c3', 'c4'] l4 = ['d1', 'd2', 'd3', 'd4'] I would like to cycle through these lists "diagonally" in groups of len(list) (in this example, each list has 4 items). cycle1: a1, b2, b3, b4 cycle2: a2, b3, c4, d1 cycle3: a3, b4, c1, d2 cycle4: a4, b1, c2, d3 The way I thought about doing this is as follows: from collections import deque from itertools import cycle l1 = deque(['a1', 'a2', 'a3', 'a4']) l2 = deque(['b1', 'b2', 'b3', 'b4']) l3 = deque(['c1', 'c2', 'c3', 'c4']) l4 = deque(['d1', 'd2', 'd3', 'd4']) l1.rotate(-0) l2.rotate(-1) l3.rotate(-2) l4.rotate(-3) groups = cycle([l1, l2, l3, l4]) In [115]: for group in groups: .: if not group: .: break .: print(group.popleft()) .: a1 b2 c3 d4 a2 b3 c4 d1 a3 b4 c1 d2 a4 b1 c2 d3 Prior to this I was mucking around with index counting while looping, and popping lists out of a deque, popping an item out of the list, and appending the list back into the deque during each iteration. Is there a better/cleaner way to do this? I was hoping for some cool itertools logic =) Thanks! -- *Pablo* -- https://mail.python.org/mailman/listinfo/python-list