Re: Cycling through iterables diagonally

2016-02-26 Thread marco . nawijn
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

2016-02-26 Thread Mark Lawrence

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

2016-02-26 Thread Peter Otten
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

2016-02-26 Thread Jussi Piitulainen
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

2016-02-25 Thread Pablo Lucena
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!


-- 
*Pabl​o​*
-- 
https://mail.python.org/mailman/listinfo/python-list