Interleaving can be thought of as two-dimensional iteration over a sequence of sequences, pulling the ith element from all n seqeuences before moving on to the ith + 1 element. Interleave does not truncate to the shortest list unlike flatten(zip(seqA, seqB)) [see flatten() recipe]. Here's an illustration:
a = [1,3,5]
b = [2,4,6,8]
c = ["x","y","z"]
interleave(a,b,c) will return:
[1, 2, "x", 3, 4, "y", 5, 6, "z", 8]
1 2 3 4 5 6 7 | def interleave(*args):
for idx in range(0, max(len(arg) for arg in args)):
for arg in args:
try:
yield arg[idx]
except IndexError:
continue
|
There are a wide variety of problems from accounting to table pretty-printing which can benefit from interleaving.
I initially wrote interleave() so that payments could be distributed evenly across line items on an invoice. Here's the scenario:
Suppose an Invoice contains two ProductOrders which each comprise two line items with accounting codes for ItemPrice and Shipping respectively. Now, as you are applying payments to this invoice, you may want to apply payments to the ItemPrice code of the first order, then to the Shipping code of the first order, and then move on to the next order. One way of handling this situation is to split line items into two separate lists by accounting code and then apply payments to the interleaved list. For example:
Order 1: ItemPrice 22.99 Shipping 0.10 Order 2: ItemPrice 43.99 Shipping 0.25
ItemPrice = [22.99, 43.99] Shipping = [0.10, 0.25]
Now when we apply_payment(interleave(ItemPrice, Shipping)) we will be distributing according to our business rule.
Similar to the roundrobin() recipe. The roundrobin recipe provides similar capabilities but works lazily and doesn't require indexing. See the collections.deque() docs at http://docs.python.org/lib/deque-recipes.html )
zip/izip. If your sequences are all the same length, a simple application of zip or izip gets you the same thing:
ANN: Device for converting rotational motion into translational by means of a circular shaped mass about an axle. Re-inventing the wheel is fun sometimes. :) The deque roundrobin() recipe is exactly what I needed. Thanks.
a simpler way. a = [1,3,5]
b = [2,4,6,8]
c = ["x","y","z"]
print [ y for x in map(None,a,b,c) for y in x if y]
wow. That's just freaky man!
So an expansion of that, without itertools would be: