How to get arrangement of two set without repeat by Python? - python

I have already got a method almost can do this:
from itertools import product
l = {1,2,3}
print(list(product(l,l)))
The output is:
[(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]
However, I don't want to the set like (1,1), (2,2), (3,3)
and (2, 3), (3, 2) should only appear once since they are same in set concept.
So the exactly output I want is:
[(1, 2), (1, 3), (2, 1), (2, 3)]
How can I do this?

A simple method iterools.combinations
>>> import itertools
>>> list(itertools.combinations({1,2,3}, 2))
[(1, 2), (1, 3), (2, 3)]
>>>

You can apply a filter. For e.g.:
>>> from itertools import product
>>> l = {1,2,3}
>>> list(filter(lambda x: [x, None][x[0] == x[1]], list(product(l,l))))
[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
>>>

Related

Numpy: reshape list of tuples

I have the following list of tuples:
>>> import itertools
>>> import numpy as np
>>> grid = list(itertools.product((1,2,3),repeat=2))
>>> grid
[(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]
I'd like to reshape this list in a sensible way (e.g. using numpy if possible) to be 3x3 as follows:
[[(1, 1), (1, 2), (1, 3)],
[(2, 1), (2, 2), (2, 3)],
[(3, 1), (3, 2), (3, 3)]]
When I do np.reshape(grid, (3, 3)) I get the following error: ValueError: cannot reshape array of size 18 into shape (3,3) (size 18??)
I've tried variations of np.reshape(grid, (3, 3, 2)) but these don't return the 3x3 grid given above.
This will do the job:
new_grid = np.empty(len(grid), dtype='object')
new_grid[:] = grid
new_grid = new_grid.reshape(3, 3)
This outputs:
array([[(1, 1), (1, 2), (1, 3)],
[(2, 1), (2, 2), (2, 3)],
[(3, 1), (3, 2), (3, 3)]], dtype=object)
The object type will remain tuple:
type(new_grid[0, 0])
tuple
18 comes from the fact that you have a list of 9 tuples, each containing 2 items; thus, 9 * 2 = 18. numpy automatically converts the tuples to part of the array.
You can either use LeonardoVaz's answer or do it speedily with nested list comprehension:
reshaped_grid = [[grid[i+j] for j in range(3)] for i in range(0, len(grid), 3)]
Output:
>>> reshaped_grid
[
[(1, 1), (1, 2), (1, 3)],
[(2, 1), (2, 2), (2, 3)],
[(3, 1), (3, 2), (3, 3)]
]

How to remove duplicate combinations tuples from python list?

I have a list with tuples as below:
mylist = [(1, 2),(1, 3),(2, 1),(2, 3),(3, 1),(3, 2),(3, 3)]
Expected (Unique combinations)
[(1, 2),(1, 3),(2, 3),(3, 3)]
I tried below
mylist = list(set(map(tuple, mylist)))
But didnt get the desired output. Any help here?
You can try this.
out=list(set(map(tuple,map(sorted,mylist))))
Thats because a Tuple (1, 2) is different from a Tuple (2, 1)
print((1, 2) == (1, 2))
print((1, 2) == (2, 1))
True
False
You can see it in:
my_set = set()
my_set.add((1, 2))
my_set.add((1, 2))
my_set.add((2, 1))
print(my_set)
{(1, 2), (2, 1)}
So, in your case, you can sort your tuples, so both (1, 2) and (2, 1) will be the same, and the set will get your job done
mylist = [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2), (3, 3)]
mylist = [sorted(item) for item in mylist]
mylist = list(set(map(tuple, mylist)))
print(mylist)
[(1, 2), (1, 3), (2, 3), (3, 3)]

Product of coordinates with specific order of iteration

Here's a snippet with a regular itertools.product usage:
from itertools import product
arr = [1,2,3]
pairs = list(product(arr, arr))
# pairs = [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]
Now I would like to have these points yielded in an order which can be achieved by sorting the resulting tuples in the following way:
sorted(pairs, key=lambda y:max(y))
# [(1, 1), (1, 2), (2, 1), (2, 2), (1, 3), (2, 3), (3, 1), (3, 2), (3, 3)]
Is there a way for me to input those numbers to itertools.product so it yields the tuples in this order, or do I need to sort the pairs after iterating over the results of itertools.product?
You can probably use your own modified approach to achieve this in one go.
sorted([(x, y) for x in [1, 2, 3] for y in [1, 2, 3]], key=lambda y:max(y))
OUTPUT
[(1, 1), (1, 2), (2, 1), (2, 2), (1, 3), (2, 3), (3, 1), (3, 2), (3, 3)]

Python implementation of set relations

How would I implement the following using python? I've tried using lambda expressions and a few other methods, but I'm not getting the desired results. Basically, I should receive a set of relations that satisfy the check. I.E they have to be divisible by each other, so {(1,1), (1,2), (1,3),...(6,6)}.
Here's the actual question:
In Python, set a variable say S = {1,2,3,4,5,6}; then do as follows: "List all the ordered pairs in the relation R = {(a,b) : a divides b} on the set {1,2,3,4,5,6}."
you can do it by list comprehension -
S = [1,2,3,4,5,6]
result = [ (x,y) for x in S for y in S if y%x==0]
You can use itertools.product within a list comprehension,and as you want they be divisible by each other you can use the condition i%j==0 or j%i==0 :
>>> from itertools import product
>>> [(i,j) for i,j in product(S,repeat=2) if i%j==0 or j%i==0]
[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 1), (2, 2), (2, 4), (2, 6), (3, 1), (3, 3), (3, 6), (4, 1), (4, 2), (4, 4), (5, 1), (5, 5), (6, 1), (6, 2), (6, 3), (6, 6)]
[{(a,b) : a/b} for a in S for b in S]

itertools.product eliminating repeated reversed tuples

I asked a question yesterday and thanks to Tim Peters, it is solved. The question is here;
itertools.product eliminating repeated elements
The new question is further version of this. This time I will generate tuples inside of tuples. Here is an example;
lis = [[(1,2), (3,4)], [(5,2), (1,2)], [(2,1), (1,2)]]
When I use it in itertools.product function this is what I get,
((1, 2), (5, 2), (2, 1))
((1, 2), (5, 2), (1, 2))
((1, 2), (1, 2), (2, 1))
((1, 2), (1, 2), (1, 2))
((3, 4), (5, 2), (2, 1))
((3, 4), (5, 2), (1, 2))
((3, 4), (1, 2), (2, 1))
((3, 4), (1, 2), (1, 2))
I want to change it in a way that if a sequence has (a,b) inside of it, then it can not have (b,a). In this example if you look at this sequence ((3, 4), (1, 2), (2, 1)) it has (1,2) and (2,1) inside of it. So, this sequence ((3, 4), (1, 2), (2, 1)) should not be considered in the results.
As I said, I asked similar question before, in that case it was not considering duplicate elements. I try to adapt it to my problem. Here is modified code. Changed parts in old version are taken in comments.
def reverse_seq(seq):
s = []
for i in range(len(seq)):
s.append(seq[-i-1])
return tuple(s)
def uprod(*seqs):
def inner(i):
if i == n:
yield tuple(result)
return
for elt in sets[i] - reverse:
#seen.add(elt)
rvrs = reverse_seq(elt)
reverse.add(rvrs)
result[i] = elt
for t in inner(i+1):
yield t
#seen.remove(elt)
reverse.remove(rvrs)
sets = [set(seq) for seq in seqs]
n = len(sets)
#seen = set()
reverse = set()
result = [None] * n
for t in inner(0):
yield t
In my opinion this code should work but I am getting error for the input lis = [[(1,2), (3,4)], [(5,2), (1,2)], [(2,1), (1,2)]]. I could not understand where I am wrong.
for i in uprod(*lis):
print i
Output is,
((1, 2), (1, 2), (1, 2))
Traceback (most recent call last):
File "D:\Users\SUUSER\workspace tree\sequence_covering _array\denemeler_buraya.py", line 39, in <module>
for i in uprod(*lis):
File "D:\Users\SUUSER\workspace tree\sequence_covering _array\denemeler_buraya.py", line 32, in uprod
for t in inner(0):
File "D:\Users\SUUSER\workspace tree\sequence_covering _array\denemeler_buraya.py", line 22, in inner
for t in inner(i+1):
File "D:\Users\SUUSER\workspace tree\sequence_covering _array\denemeler_buraya.py", line 25, in inner
reverse.remove(rvrs)
KeyError: (2, 1)
Thanks,
The problem is that you unconditionally do reverse.remove(rvrs), even if rvrs was already in reverse before you (redundantly) added it. So insert:
remove_later = rvrs not in reverse
before:
reverse.add(rvrs)
and change the removal code to:
if remove_later:
reverse.remove(rvrs)
Then the output is:
((1, 2), (1, 2), (1, 2))
((1, 2), (5, 2), (1, 2))
((3, 4), (1, 2), (1, 2))
((3, 4), (5, 2), (1, 2))
((3, 4), (5, 2), (2, 1))
Unrelatedly, you can throw away the reverse_seq() function and write this instead:
rvrs = elt[::-1]
I’m doing it a bit differently, using sets to get rid of the order where the order is not necessary. Actually using frozensets, so we can easily nest them.
First of all, we convert the lis into a list of lists of (frozen)sets, because the order of the numbers of the tuples should be ignored.
>>> lis = [[(1,2), (3,4)], [(5,2), (1,2)], [(2,1), (1,2)]]
>>> lis_ = [[frozenset(x) for x in y] for y in lis]
Next, we create the product, and then put the result in a set, so we get rid of duplicates:
>>> result = set(x for x in itertools.product(*lis_))
>>> result
{(frozenset({3, 4}), frozenset({1, 2}), frozenset({1, 2})), (frozenset({1, 2}), frozenset({1, 2}), frozenset({1, 2})), (frozenset({3, 4}), frozenset({2, 5}), frozenset({1, 2})), (frozenset({1, 2}), frozenset({2, 5}), frozenset({1, 2}))}
And we are already done. If you print those now, and make it a bit prettier (getting rid of the frozenset() part in the output, you have your result:
>>> for r in result:
print([tuple(x) for x in r])
[(3, 4), (1, 2), (1, 2)]
[(1, 2), (1, 2), (1, 2)]
[(3, 4), (2, 5), (1, 2)]
[(1, 2), (2, 5), (1, 2)]
Different solution which just filters the results from itertools.product:
>>> lis = [[(1,2), (3,4)], [(5,2), (1,2)], [(2,1), (1,2)]]
>>> seenProducts = set()
>>> for p in itertools.product(*lis):
product = tuple(frozenset(x) for x in p)
if product not in seenProducts:
seenProducts.add(product)
print(p) # print original product
((1, 2), (5, 2), (2, 1))
((1, 2), (1, 2), (2, 1))
((3, 4), (5, 2), (2, 1))
((3, 4), (1, 2), (2, 1))

Categories

Resources