I need to iterate over n consecutive elements in a list.
For example:
data = [1,2,3,4,5,6,7]
I need to go over:
1 2
2 3
3 4
4 5
or:
1 2 3
2 3 4
3 4 5
4 5 6
Is there zip function to do that?
I'm not sure exactly what you're looking for, but try this:
data = [1, 2, 3, 4, 5, 6, 7]
n = 3
[data[i:i+n] for i in range(len(data) - n + 1)]
# [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7]]
Or:
f = lambda data, n: [data[i:i+n] for i in range(len(data) - n + 1)]
for x, y, z in f([1, 2, 3, 4, 5, 6, 7], 3):
print x, y, z
Assuming you are always doing this for a list or another sequence and it does not need to work with arbitrary iterables:
def group(seq, n):
return (seq[i:i+n] for i in range(len(seq)-n+1))
Examples:
>>> list(group([1,2,3,4,5,6,7], 2))
[[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7]]
>>> list(group([1,2,3,4,5,6,7], 3))
[[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7]]
If you need to do this for any arbitrary iterable (that may not support len() or slicing), you can adapt the pairwise recipe:
from itertools import tee, izip
def group(iterable, n):
"group(s, 3) -> (s0, s1, s2), (s1, s2, s3), (s2, s3, s4), ..."
itrs = tee(iterable, n)
for i in range(1, n):
for itr in itrs[i:]:
next(itr, None)
return izip(*itrs)
>>> list(group(iter([1,2,3,4,5,6,7]), 2))
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]
>>> list(group(iter([1,2,3,4,5,6,7]), 3))
[(1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6), (5, 6, 7)]
Specific answer:
>>> zip(data,data[1:])
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]
General answer:
>>> def consecutives(data,per_set):
... return zip(*[data[n:] for n in range(per_set)])
...
>>> consecutives(range(1,8),2)
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]
>>> consecutives(range(1,8),3)
[(1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6), (5, 6, 7)]
>>> consecutives(range(1,8),4)
[(1, 2, 3, 4), (2, 3, 4, 5), (3, 4, 5, 6), (4, 5, 6, 7)]
Depending on whether you want to iterate over the sub-lists or a flat list:
from itertools import chain
for x in chain(*[ a[i:i+n] for i in xrange(len(a)-n+1) ]):
print x
Or:
for x in [ a[i:i+n] for i in xrange(len(a)-n+1) ]:
print x
Probably not the best way, but still useful:
>>> data = [1,2,3,4,5,6,7]
>>> map(None,data[:-1],data[1:])
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]
>>> map(None,data[:-2],data[1:-1],data[2:])
[(1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6), (5, 6, 7)]
This is a fairly simple task to program yourself. I dont think there is a pre-canned function to do this.
def func(arr,n):
i = 0
while i+n < len(arr):
for range(i,i+n):
.... make stuff here....
i = i + 1
Related
I am new to Python and I would like to combine two arrays. I have two arrays: A and B and would like to get array C as follows:
A = [1, 2, 3, 4, 5]
B = [6, 7, 8, 9, 10]
Result array:
C = [(1, 6), (2, 7), (3, 8), (4, 9), (5, 10)]
Use zip, the built-in for pairwise iteration:
C = list(zip(A, B))
Note that you are not concatenating the two lists.
Without any dependency:
>>> A = [1, 2, 3, 4, 5]
>>> B = [6, 7, 8, 9, 10]
>>> C = [(A[i], B[i]) for i in range(len(A))]
>>> C
[(1, 6), (2, 7), (3, 8), (4, 9), (5, 10)]
I've just written some code to convert a list of points into a list of to/from tuples but it doesn't feel very efficient.
I was wondering if anyone had any suggestions to make this more concise?
from_point, to_point = None, None
point_list = []
for p in [1, 5, 2, 4, 7, 9]:
to_point = p
if from_point and to_point:
point_list.append((from_point, to_point))
from_point = to_point
print(point_list)
Input: [1, 5, 2, 4, 7, 9]
Output: [(1, 5), (5, 2), (2, 4), (4, 7), (7, 9)]
Edit: Changed points to be non sequential.
You can always use zip:
>>> p = [1, 5, 2, 4, 7, 9]
>>> point_list = list(zip(p[:-1], p[1:]))
>>> print(point_list)
[(1, 5), (5, 2), (2, 4), (4, 7), (7, 9)]
An alternative one line solution
input = [1, 2, 3, 4, 5, 6]
output = [(input[index], input[index+1]) for index in range(len(list)-1)]
print(output)
What about this?
x=[1, 5, 2, 4, 7, 9]
print [ tuple(x[i:i+2]) for i in xrange(len(x)-1) ]
Using more_itertools:
import more_itertools as mit
list(mit.pairwise([1, 5, 2, 4, 7, 9]))
# [(1, 5), (5, 2), (2, 4), (4, 7), (7, 9)]
How to generate something like
[(), (1,), (1,2), (1,2,3)..., (1,2,3,...n)]
and
[(), (4,), (4,5), (4,5,6)..., (4,5,6,...m)]
then take the product of them and merge into
[(), (1,), (1,4), (1,4,5), (1,4,5,6), (1,2), (1,2,4)....(1,2,3,...n,4,5,6,...m)]
?
For the first two lists I've tried the powerset recipe in https://docs.python.org/2/library/itertools.html#recipes , but there will be something I don't want, like (1,3), (2,3)
For the product I've tested with chain and product, but I just can't merge the combinations of tuples into one.
Any idea how to do this nice and clean? Thanks!
Please note that, single element tuples are denoted like this (1,).
a = [(), (1,), (1, 2), (1, 2, 3)]
b = [(), (4,), (4, 5), (4, 5, 6)]
from itertools import product
for item1, item2 in product(a, b):
print item1 + item2
Output
()
(4,)
(4, 5)
(4, 5, 6)
(1,)
(1, 4)
(1, 4, 5)
(1, 4, 5, 6)
(1, 2)
(1, 2, 4)
(1, 2, 4, 5)
(1, 2, 4, 5, 6)
(1, 2, 3)
(1, 2, 3, 4)
(1, 2, 3, 4, 5)
(1, 2, 3, 4, 5, 6)
If you want them in a list, you can use list comprehension like this
from itertools import product
print [sum(items, ()) for items in product(a, b)]
Or even simpler,
print [items[0] + items[1] for items in product(a, b)]
You can try like this,
>>> a=[(), (1,), (1,2), (1,2,3)]
>>> b=[(), (4,), (4,5), (4,5,6)]
>>> for ix in a:
... for iy in b:
... print ix + iy
...
()
(4,)
(4, 5)
(4, 5, 6)
(1,)
(1, 4)
(1, 4, 5)
(1, 4, 5, 6)
(1, 2)
(1, 2, 4)
(1, 2, 4, 5)
(1, 2, 4, 5, 6)
(1, 2, 3)
(1, 2, 3, 4)
(1, 2, 3, 4, 5)
(1, 2, 3, 4, 5, 6)
If you don't want to use any special imports:
start = 1; limit = 10
[ range(start, start + x) for x in range(limit) ]
With start = 1 the output is:
[[], [1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7, 8, 9]]
If you want to take the product, maybe using itertools might be most elegant.
How can I skip the tuples which has duplicate elements in the iteration when I use itertools.product? Or let's say, is there anyway not to look at them in the iteration? Because skipping may be time consuming if the number of lists are too much.
Example,
lis1 = [1,2]
lis2 = [2,4]
lis3 = [5,6]
[i for i in product(lis1,lis2,lis3)] should be [(1,2,5), (1,2,6), (1,4,5), (1,4,6), (2,4,5), (2,4,6)]
It will not have (2,2,5) and (2,2,6) since 2 is duplicate in here. How can I do that?
itertools generally works on unique positions within inputs, not on unique values. So when you want to remove duplicate values, you generally have to either post-process the itertools result sequence, or "roll your own". Because post-processing can be very inefficient in this case, roll your own:
def uprod(*seqs):
def inner(i):
if i == n:
yield tuple(result)
return
for elt in sets[i] - seen:
seen.add(elt)
result[i] = elt
for t in inner(i+1):
yield t
seen.remove(elt)
sets = [set(seq) for seq in seqs]
n = len(sets)
seen = set()
result = [None] * n
for t in inner(0):
yield t
Then, e.g.,
>>> print list(uprod([1, 2, 1], [2, 4, 4], [5, 6, 5]))
[(1, 2, 5), (1, 2, 6), (1, 4, 5), (1, 4, 6), (2, 4, 5), (2, 4, 6)]
>>> print list(uprod([1], [1, 2], [1, 2, 4], [1, 5, 6]))
[(1, 2, 4, 5), (1, 2, 4, 6)]
>>> print list(uprod([1], [1, 2, 4], [1, 5, 6], [1]))
[]
>>> print list(uprod([1, 2], [3, 4]))
[(1, 3), (1, 4), (2, 3), (2, 4)]
This can be much more efficient, since a duplicate value is never even considered (neither within an input iterable, nor across them).
lis1 = [1,2]
lis2 = [2,4]
lis3 = [5,6]
from itertools import product
print [i for i in product(lis1,lis2,lis3) if len(set(i)) == 3]
Output
[(1, 2, 5), (1, 2, 6), (1, 4, 5), (1, 4, 6), (2, 4, 5), (2, 4, 6)]
With itertools.combinations there will be no repeated elements in sorted order:
>>> lis = [1, 2, 4, 5, 6]
>>> list(itertools.combinations(lis, 3))
[(1, 2, 4), (1, 2, 5), (1, 2, 6), (1, 4, 5), (1, 4, 6), (1, 5, 6), (2, 4, 5),
(2, 4, 6), (2, 5, 6), (4, 5, 6)]
How can i get this
nums = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8)]
to this? The second item of each tuple is the first item of the next tuple.
[0, 1, 2, 3, 4, 5, 6, 7, 8]
I did:
>>> zip(*nums)[0]
(0, 1, 2, 3, 4, 5, 6, 7)
But it gives me everything except the last element and then i had to use some bad code to get it to the correct result so i was looking for an elegant solution.
Not sure what your general case is, but
[nums[0][0]] + [x[1] for x in nums]
For your example
range(nums[-1][-1] + 1)
also works, can you describe what you are trying to do rather than just giving one simple case?
>>> nums = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8)]
>>> i = iter(nums)
>>> next(i) + tuple(y for x,y in i)
(0, 1, 2, 3, 4, 5, 6, 7, 8)
More efficient version using itertools
>>> from itertools import chain
>>> nums = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8)]
>>> i = iter(nums)
>>> list(chain(next(i),(y for x,y in i)))
[0, 1, 2, 3, 4, 5, 6, 7, 8]
def flatten(E):
if E in [[], ()]:
return []
elif type(E) not in [list, tuple]:
return [E]
else:
return flatten(E[0]) + flatten(E[1:])
def declutter(L):
s = set()
answer = []
for i in L:
if i not in s:
s.add(i)
answer.append(i)
return answer
>>> nums = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8)]
>>> declutter(flatten(nums))
[0, 1, 2, 3, 4, 5, 6, 7, 8]
Hope this helps