itertools.product eliminating repeated elements - python

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)]

Related

Print consecutive pair of subsets with increasing size from a given list of numbers

Example 1,
Input: [a,b,c,d]
Output: [[a],[a,b],[b,c],[c,d],[a,b,c],[b,c,d],[a,b,c,d]]
Example 2,
Input: [1,2,3,4,5]
Output: [[1],[1,2],[2,3],[3,4],[4,5],[1,2,3],[2,3,4],[3,4,5],[1,2,3,4],[2,3,4,5],[1,2,3,4,5]]
In the same way, the number of elements in the pair starting from 1 increases till 'n'(size of the given list)
Is there a possible way of handling, a given list of any size (If possible in Python)
Extra Info:
I have tried this code, which returns pair of 3 elements in the output but I want to return first 1 element, next with 2 elements, till n-1 elements as I mentioned above in the example
Input:
listA = [51,23,11,45]
res = [[listA[i], listA[i + 1],listA[i + 2]] for i in range(len(listA) - 2)]
print("List with paired elements: \n",res)
Output:
List with paired elements: [[51, 23, 11], [23, 11, 45]]
Fisrt way
You can do it automatically using a package more_itertools.substrings:
import more_itertools
list(more_itertools.substrings([2,3,5,7,11]))
Output:
[(2,), (3,), (5,), (7,), (11,), (2, 3), (3, 5), (5, 7), (7, 11), (2, 3, 5), (3, 5, 7), (5, 7, 11), (2, 3, 5, 7), (3, 5, 7, 11), (2, 3, 5, 7, 11)]
You could also check a source code of implementation of this method or make it yourself as an exercise.
Second way
It allows you to achieve exactly what you expect using more_itertools.sliding_window:
from itertools import chain
from more_itertools import sliding_window
x = [2,3,5,7,11]
first_part = [(x[0],)]
second_part = [sliding_window(x, n) for n in range(2, len(x)+1)]
list(chain(first_part, *second_part))
Output:
[(2,), (2, 3), (3, 5), (5, 7), (7, 11), (2, 3, 5), (3, 5, 7), (5, 7, 11), (2, 3, 5, 7), (3, 5, 7, 11), (2, 3, 5, 7, 11)]
I am a bit confused about the output requirement, but here is something that produces the result I think you are looking for:
def get_list_of_size(l, n):
return [l[i:i+n] for i in range(len(l)-n+1)]
def get_consecutive_ss(l):
output=[]
for i in range(len(l)):
output+=get_list_of_size(l, i+1)
return [output[0]]+output[len(l):]
l = [1,2,3,4,5]
l2=['a','b','c','d']
print(get_consecutive_ss(l))
print(get_consecutive_ss(l2))
Output:
[[1], [1, 2], [2, 3], [3, 4], [4, 5], [1, 2, 3], [2, 3, 4], [3, 4, 5], [1, 2, 3, 4], [2, 3, 4, 5], [1, 2, 3, 4, 5]]
[['a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['a', 'b', 'c'], ['b', 'c', 'd'], ['a', 'b', 'c', 'd']]

Combination of List and Nested List by Index

The output of my script is a list and a nested list. I would like to get the combinations of the two lists by index. In this instance, I have the following two lists:
x = [0, 1, 2, 3]
y = [[0, 1, 2, 3],
[0, 1, 2, 3, 4, 5, 6, 7, 8],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4, 5, 6, 7, 8]]
The desired output should look something like this.
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1,
7), (1, 8), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5),
(3, 6), (3, 7), (3, 8)]
I've looked at many posts about itertools.combinations and itertools.product, but I cannot find anything about looping and combining at the same time, which I think would be the approach to the problem. I want to get all combinations x[0] and y[0], then x[1] and y[1], etc.
You can do this with a list comprehension.
x = [0, 1, 2, 3]
y = [[0, 1, 2, 3],
[0, 1, 2, 3, 4, 5, 6, 7, 8],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4, 5, 6, 7, 8]]
final = [(i,j) for i in x for j in y[i]]
It seems you are going to do the catidion multiplication of two array. Here is the reference check and let me know if worked for you.
Cartesian product of x and y array points into single array of 2D points

Converting list of points to list of tuples in python

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)]

Generate a lattice using python

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.

python looping over n consecutive items in a list

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

Categories