Compare keys and values within the same dictionary - python

{(0, 0): {(0, 1), (1, 0)},
(0, 3): {(0, 2), (0, 4), (1, 3)},
(0, 4): {(0, 3), (1, 4)},
(1, 1): {(0, 1), (1, 0), (1, 2), (2, 1)},
(1, 2): {(0, 2), (1, 1), (1, 3), (2, 2)},
(2, 0): {(1, 0), (2, 1), (3, 0)},
(2, 2): {(1, 2), (2, 1), (2, 3), (3, 2)},
(2, 3): {(1, 3), (2, 2), (2, 4), (3, 3)},
(2, 4): {(1, 4), (2, 3), (3, 4)},
(3, 0): {(2, 0), (3, 1)},
(3, 1): {(2, 1), (3, 0), (3, 2)},
(3, 3): {(2, 3), (3, 2), (3, 4)}}
Above is a dictionary that I have obtained from a 2D List:
keys -- tuples (co-ordinates)
values -- set of tuples (co-ordinates)
The co-ordinates are cells in the 2D list.
My goal is to compare the value of given key with next key.
example: compare {(0, 2), (0, 4), (1, 3)} with (0, 4).
If the key is present in the value of the previous key then I would like to update the first value with values of the key that was found. For the given example: the result should be something like: {(0, 2), (0, 4), (1, 3), (0, 3), (1, 4)}.
I would like to know if this is even possible? Is there a way to compare values of a dictionary with keys of the same dictionary?
I was also thinking of using DFS but I do not have all the vertices for that. Is DFS the right approach?

If you only want to do this to a given keys value then you could make a function to do this:
def get_value(data, key):
keys = tuple(data)
value = data[key]
next_value = keys[keys.index(key)+1]
next_value = data[next_value]
return value | next_value if key in value else value | next_value
You can use it like this:
get_value(data, (0, 3))
#{(1, 3), (1, 4), (0, 4), (0, 3), (0, 2)}
If you want to do this to the whole dict then you could make a lookahead iterator, and compare them that way:
from itertools import zip_longest
data = {(0, 0): {(0, 1), (1, 0)},
(0, 3): {(0, 2), (0, 4), (1, 3)},
(0, 4): {(0, 3), (1, 4)},
(1, 1): {(0, 1), (1, 0), (1, 2), (2, 1)},
(1, 2): {(0, 2), (1, 1), (1, 3), (2, 2)},
(2, 0): {(1, 0), (2, 1), (3, 0)},
(2, 2): {(1, 2), (2, 1), (2, 3), (3, 2)},
(2, 3): {(1, 3), (2, 2), (2, 4), (3, 3)},
(2, 4): {(1, 4), (2, 3), (3, 4)},
(3, 0): {(2, 0), (3, 1)},
(3, 1): {(2, 1), (3, 0), (3, 2)},
(3, 3): {(2, 3), (3, 2), (3, 4)}}
lookahead = iter(data.items()); next(lookahead)
for (k,v), (_k, _v) in zip_longest(data.items(), lookahead, fillvalue=(None,None)):
if all((_k, _v)) and v >= {_k}:
v |= _v
This results in:
{(0, 0): {(0, 1), (1, 0)},
(0, 3): {(1, 3), (1, 4), (0, 4), (0, 3), (0, 2)},
(0, 4): {(0, 3), (1, 4)},
(1, 1): {(1, 3), (0, 2), (2, 1), (1, 0), (0, 1), (1, 2), (2, 2), (1, 1)},
(1, 2): {(1, 3), (1, 1), (0, 2), (2, 2)},
(2, 0): {(3, 0), (1, 0), (2, 1)},
(2, 2): {(3, 2), (1, 3), (2, 1), (2, 3), (1, 2), (3, 3), (2, 2), (2, 4)},
(2, 3): {(1, 3), (3, 3), (1, 4), (2, 3), (2, 2), (3, 4), (2, 4)},
(2, 4): {(3, 4), (2, 3), (1, 4)},
(3, 0): {(3, 2), (3, 0), (3, 1), (2, 1), (2, 0)},
(3, 1): {(3, 0), (3, 2), (2, 1)},
(3, 3): {(3, 4), (3, 2), (2, 3)}}
Note if you’re using python 3 you shouldn’t have an issue with ordering otherwise it’s safest to ensure the dict is in correct order and use a collections.OrderedDict especially in py2

Related

How to return a new list of lists in python correctly [duplicate]

I try to solve a problem and one part of it is to find all paths from (0, 0) to the right most point of the 2d array. This is my code:
def route_finder_helper(x, y, current_path, filler, list_of_lists):
current_path[filler] = (x, y)
if x == 0 and y == 0:
print(current_path)
list_of_lists.append(current_path)
return list_of_lists
if x == 0:
return route_finder_helper(x, y - 1, current_path, filler - 1, list_of_lists)
if y == 0:
return route_finder_helper(x - 1, y, current_path, filler - 1, list_of_lists)
return route_finder_helper(x-1, y, current_path, filler - 1, list_of_lists) + \
route_finder_helper(x, y-1, current_path, filler - 1, list_of_lists)
where x and y is current coordinate, current_path is a list of tuples of the current path, filler is index what position of the list to change and list_of_lists should be all the paths. However, when I run this program and print the return value I get this output:
[(0, 0), (0, 1), (0, 2), (1, 2), (2, 2)]
[(0, 0), (0, 1), (1, 1), (1, 2), (2, 2)]
[(0, 0), (1, 0), (1, 1), (1, 2), (2, 2)]
[(0, 0), (0, 1), (1, 1), (2, 1), (2, 2)]
[(0, 0), (1, 0), (1, 1), (2, 1), (2, 2)]
[(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)]
[[(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)]]
So I get the correct paths, but I do not know how to save them to the list of lists. Could someone help me?
This is how I call my function:
x_coordinate = coordinates[0]
y_coordinate = coordinates[1]
path_length = (x_coordinate + 1) + (y_coordinate + 1) - 1
start_filling = path_length - 1
current_path = [0] * path_length
paths = route_finder_helper(x_coordinate, y_coordinate, current_path,
start_filling, [])
This is what it should return:
[[(0, 0), (0, 1), (0, 2), (1, 2), (2, 2)],[(0, 0), (0, 1), (1, 1), (1, 2), (2, 2)], [(0, 0), (1, 0), (1, 1), (1, 2), (2, 2)], [(0, 0), (0, 1), (1, 1), (2, 1), (2, 2)], [(0, 0), (1, 0), (1, 1), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)]]
This is the corrected answer:
def route_finder_helper(x, y, current_path, filler, list_of_lists):
current_path[filler] = (x, y)
if x == 0 and y == 0:
return list_of_lists + [current_path[:]]
if x == 0:
return route_finder_helper(x, y - 1, current_path, filler - 1, list_of_lists)
if y == 0:
return route_finder_helper(x - 1, y, current_path, filler - 1, list_of_lists)
return route_finder_helper(x-1, y, current_path, filler - 1, list_of_lists) + \
route_finder_helper(x, y-1, current_path, filler - 1, list_of_lists)
x_coordinate = 2
y_coordinate = 2
path_length = (x_coordinate + 1) + (y_coordinate + 1) - 1
start_filling = path_length - 1
current_path = [0] * path_length
paths = route_finder_helper(x_coordinate, y_coordinate, current_path, start_filling, [])
print(paths)
Output:
[[(0, 0), (0, 1), (0, 2), (1, 2), (2, 2)],
[(0, 0), (0, 1), (1, 1), (1, 2), (2, 2)],
[(0, 0), (1, 0), (1, 1), (1, 2), (2, 2)],
[(0, 0), (0, 1), (1, 1), (2, 1), (2, 2)],
[(0, 0), (1, 0), (1, 1), (2, 1), (2, 2)],
[(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)]]
The correction here is:
return list_of_lists + [current_path[:]]
where I add a copy by using current_path[:]
The logic of the code is correct, the problem that you have is that you are dealing with a list which is a mutable item. This means that every variable which has a reference to the list, gets an updated list when you change it for only one variable:
a = [1, 2, 3]
b = a
a[0] = -1
print(b)
>>> [-1, 2, 3]
Something like this also happens in your code when you append to the list_of_lists. Simply changing the append to this:
# return list_of_lists.append(current_path) <- old code
return list_of_lists + [current_path] <- new code
This guarantees that you start a new list every time the code ends up there, instead of appending to a list where other parts of the code have a reference to as well.
If this is a new concept for you in Python there are plenty of nice blogs which explain this in more detail than me, e.g. here
complete code:
def route_finder_helper(x, y, current_path, filler, list_of_lists):
current_path[filler] = (x, y)
if x == 0 and y == 0:
return list_of_lists + [current_path]
if x == 0:
return route_finder_helper(x, y - 1, current_path, filler - 1, list_of_lists)
if y == 0:
return route_finder_helper(x - 1, y, current_path, filler - 1, list_of_lists)
return route_finder_helper(x-1, y, current_path, filler - 1, list_of_lists) + \
route_finder_helper(x, y-1, current_path, filler - 1, list_of_lists)
x_coordinate = 2
y_coordinate = 2
path_length = (x_coordinate + 1) + (y_coordinate + 1) - 1
start_filling = path_length - 1
current_path = [0] * path_length
paths = route_finder_helper(x_coordinate, y_coordinate, current_path, start_filling, [])
print(paths)
>>> [[(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)]]

Looking to return all possible rolls of two dice. The return value is a list which contains tuples

I am currently trying to understand how to nest two for loops together before utilizing any comprehension loops. My mission is to return a list of every combination as a tuple, instead i am receiving a list of 6 lists, when i want a list of 36 combinations.
I have tried to iterate over the two ranges.
def build_roll_permutations():
dice = []
for i in range(1,7):
dicee = []
for j in range(1,7):
dicee.append((i,j))
dice.append(dicee)
return dice
expected results:
[(1,1),(1,2)(1,3)...etc]
my results:
[[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6)], [(2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6)], [(3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6)], [(4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6)], [(5, 1), (5, 2), (5, 3), (5, 4), (5, 5), (5, 6)], [(6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6)]]
Just get rid of dicee and append directly to dice.
def build_roll_permutations():
dice = []
for i in range(1,7):
for j in range(1,7):
dice.append((i,j))
return dice
Note you can do this with a simple list comprehension
def build_roll_permuatations():
return [(i,j) for i in range(1,7) for j in range(1,7)]
or itertools.product (since this is, in fact, a product and not a permutation):
def build_rolls():
return list(product(range(1,7), repeat=2))
Use extend instead of append, when modifying dice:
def build_roll_permutations():
dice = []
for i in range(1, 7):
dicee = []
for j in range(1, 7):
dicee.append((i, j))
dice.extend(dicee) # line to fix
return dice
print(build_roll_permutations())
Output
[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5), (5, 6), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6)]

networkx edges return wrong indices

I started using python and networkx from a few days.
I have an unoriented graph and I try to iterate on the edges incident to a node.
I used
print (G.edges)
for i in G.nodes:
print( G.edges(i))
obtaining
[(0, 1), (0, 2), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
[(0, 1), (0, 2), (0, 4)]
[(1, 0), (1, 2), (1, 3), (1, 4)]
[(2, 0), (2, 1), (2, 3), (2, 4)]
[(3, 1), (3, 2), (3, 4)]
[(4, 0), (4, 1), (4, 2), (4, 3)]
The edges provided by G.edges() have the two nodes reversed in some cases (e.g., for i=1 I have edge (1,0), but it does not exist !! I have only (0,1). Since the graph is unoriented, it is the same edge, but if I try to use it as the index of a vector of the edges it does not work.
I tried
for i in G. nodes
... do something with .... x[e] for e in G.edges(i)
You can extend the list of G.edges() to be in both direction
a = [e for e in G.edges]
gives you the list of edges [(0, 1), (0, 2), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] which removes duplicate representations of undirected edges while neighbor reporting across all nodes will naturally report both directions, according to networkx Documentation.
You can either:
1) duplicate the list by adding edges representation in reversed order
a = [e for e in G.edges] + [(y, x) for (x, y) in G.edges]
which gives you
[(0, 1), (0, 2), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4), (1, 0), (2, 0), (4, 0), (2, 1), (3, 1), (4, 1), (3, 2), (4, 2), (4, 3)]
or; 2) use list comprehension to get edges from G.edges(i) like you did:
b = [e for i in G.nodes for e in G.edges(i)]
output:
[(0, 1), (0, 2), (0, 4), (1, 0), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 3), (2, 4), (3, 1), (3, 2), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3)]

Apply sum distrutively to tuples

I'd like to have an algorithm which calculates the transitions from these STATE/ACTIONS tuples. For example, if you are in state (2,1) you can transition to states [(2,2),(2,0)]. This is calculated by adding the actions [(0,1),(-1,0)], to the state (2,1). I'm somewhat new to python so I'm wondering what the most efficient way to do this is. I would end up with a dict similar to the ACTIONS dict. Thanks!!
STATES=[
(0,0),
(0,1),
(0,2),
(0,3),
(1,0),
# '1,1',
(1,2),
(1,3),
(2,0),
(2,1),
(2,2),
(2,3)
]
ACTIONS={
(0,0):[(0,1),(1,0)],
(0,1):[(0,1),(0,-1)],
(0,2):[(0,-1),(1,0),(0,1)],
(0,3):[(0,-1),(1,0)],
(1,0):[(1,0),(-1,0)],
# '1,1':0,
(1,2):[(1,0),(-1,0),(0,1)],
(1,3):[],
(2,0):[(0,1),(-1,0)],
(2,1):[(0,1),(0,-1)],
(2,2):[(0,-1),(-1,0),(0,1)],
(2,3):[]
}
You can set up a list of possible offsets corresponding to the actions available. From there, you build a dictionary of actions using the state as key.
STATES=[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)]
offsets = [(0, 1),(-1, 0), (1, 1), (-1, -1)]
actions = {}
for state in STATES:
actions[state] = [(state[0] + off0, state[1] + off1) for off0, off1 in offsets]
actions
output:
{(0, 0): [(0, 1), (-1, 0), (1, 1), (-1, -1)],
(0, 1): [(0, 2), (-1, 1), (1, 2), (-1, 0)],
(0, 2): [(0, 3), (-1, 2), (1, 3), (-1, 1)],
(0, 3): [(0, 4), (-1, 3), (1, 4), (-1, 2)],
(1, 0): [(1, 1), (0, 0), (2, 1), (0, -1)],
(1, 2): [(1, 3), (0, 2), (2, 3), (0, 1)],
(1, 3): [(1, 4), (0, 3), (2, 4), (0, 2)],
(2, 0): [(2, 1), (1, 0), (3, 1), (1, -1)],
(2, 1): [(2, 2), (1, 1), (3, 2), (1, 0)],
(2, 2): [(2, 3), (1, 2), (3, 3), (1, 1)],
(2, 3): [(2, 4), (1, 3), (3, 4), (1, 2)]}

All possible ways to place colored balls into bins

I have a number of bins. Each bin accommodates only one ball.
Let's say, I have
Na number of red balls
Nb number of blue balls
Nc number of green balls
and so on.
I want to find out all possible ways of placing the balls into bins of length (Na+Nb+Nc).
For example, let's say I have only two red balls and two blue balls. I want to place them into 4 bins. The possible ways of arrangements are:
R R B B
R B R B
R B B R
B R R B
B R B R
B B R R
( I hope I did not miss any combination)
Is there any easy way to generate the indices for the different colors, for example:
First row is : R=(0,1) B=(2,3)
Second row is : R=(0,2) B=(1,3)
Is there an easy way to generate this in numpy?
The bins actually have different weights, something like:
[0.1, 0.3, 0.2, 0.5]
So for the combination R R B B represented as R at (0,1) and B at (2,3) , the total weight for R is 0.1+0.3=0.4 and for B is 0.2+0.5=0.7
I ultimately am interested in the total weight for each color in the different arrangements and want to choose the best one from another cost function f(total_weight(R), total_weight(B)). Any comments if the generation of total weight could be done in a different easy way in numpy?
Here's a "multi-combinations" implementation that doesn't require eliminating duplicate permutations. The first argument, n, is the list [Na, Nb, Nc, ...].
It is implemented as a recursive generator, so you can iterate through the combinations without having them all in memory at once. You say in a comment that Na + Nb + ... is typically around 20 but could be as high as 50 or 100. That means you almost certainly do not want to store all the combinations in memory. Consider an example with four "colors" where Na = Nb = Nc = Nd = 5. The number of combinations is choose(20, 5) * choose(15, 5) * choose(10, 5) = 11732745024, where choose(n, k) is the binomial coefficient. My computer has just 16 GB of RAM, so the storage required for that number of combinations would far exceed my computer's memory.
from itertools import combinations
def multicombinations(n, bins=None):
if bins is None:
bins = set(range(sum(n)))
if len(n) == 0:
yield []
else:
for c in combinations(bins, n[0]):
for t in multicombinations(n[1:], bins - set(c)):
yield [c] + t
It generates a list of tuples. That is, where your description of the first row is "First row is : R=(0,1) B=(2,3)", the first value generated by multicombinations([2, 2]) is [(0, 1), (2, 3)]. (This might not be the best format for the result, given the description of the weight calculation that you want to do next.)
Some examples:
In [74]: list(multicombinations([2, 2]))
Out[74]:
[[(0, 1), (2, 3)],
[(0, 2), (1, 3)],
[(0, 3), (1, 2)],
[(1, 2), (0, 3)],
[(1, 3), (0, 2)],
[(2, 3), (0, 1)]]
In [75]: list(multicombinations([3, 2]))
Out[75]:
[[(0, 1, 2), (3, 4)],
[(0, 1, 3), (2, 4)],
[(0, 1, 4), (2, 3)],
[(0, 2, 3), (1, 4)],
[(0, 2, 4), (1, 3)],
[(0, 3, 4), (1, 2)],
[(1, 2, 3), (0, 4)],
[(1, 2, 4), (0, 3)],
[(1, 3, 4), (0, 2)],
[(2, 3, 4), (0, 1)]]
In [76]: list(multicombinations([2, 3, 2]))
Out[76]:
[[(0, 1), (2, 3, 4), (5, 6)],
[(0, 1), (2, 3, 5), (4, 6)],
[(0, 1), (2, 3, 6), (4, 5)],
[(0, 1), (2, 4, 5), (3, 6)],
[(0, 1), (2, 4, 6), (3, 5)],
[(0, 1), (2, 5, 6), (3, 4)],
[(0, 1), (3, 4, 5), (2, 6)],
[(0, 1), (3, 4, 6), (2, 5)],
[(0, 1), (3, 5, 6), (2, 4)],
[(0, 1), (4, 5, 6), (2, 3)],
[(0, 2), (1, 3, 4), (5, 6)],
[(0, 2), (1, 3, 5), (4, 6)],
[(0, 2), (1, 3, 6), (4, 5)],
[(0, 2), (1, 4, 5), (3, 6)],
[(0, 2), (1, 4, 6), (3, 5)],
[(0, 2), (1, 5, 6), (3, 4)],
[(0, 2), (3, 4, 5), (1, 6)],
[(0, 2), (3, 4, 6), (1, 5)],
[(0, 2), (3, 5, 6), (1, 4)],
[(0, 2), (4, 5, 6), (1, 3)],
[(0, 3), (1, 2, 4), (5, 6)],
[(0, 3), (1, 2, 5), (4, 6)],
[(0, 3), (1, 2, 6), (4, 5)],
[(0, 3), (1, 4, 5), (2, 6)],
[(0, 3), (1, 4, 6), (2, 5)],
[(0, 3), (1, 5, 6), (2, 4)],
[(0, 3), (2, 4, 5), (1, 6)],
[(0, 3), (2, 4, 6), (1, 5)],
[(0, 3), (2, 5, 6), (1, 4)],
[(0, 3), (4, 5, 6), (1, 2)],
[(0, 4), (1, 2, 3), (5, 6)],
[(0, 4), (1, 2, 5), (3, 6)],
[(0, 4), (1, 2, 6), (3, 5)],
[(0, 4), (1, 3, 5), (2, 6)],
[(0, 4), (1, 3, 6), (2, 5)],
[(0, 4), (1, 5, 6), (2, 3)],
[(0, 4), (2, 3, 5), (1, 6)],
[(0, 4), (2, 3, 6), (1, 5)],
[(0, 4), (2, 5, 6), (1, 3)],
[(0, 4), (3, 5, 6), (1, 2)],
[(0, 5), (1, 2, 3), (4, 6)],
[(0, 5), (1, 2, 4), (3, 6)],
[(0, 5), (1, 2, 6), (3, 4)],
[(0, 5), (1, 3, 4), (2, 6)],
[(0, 5), (1, 3, 6), (2, 4)],
[(0, 5), (1, 4, 6), (2, 3)],
[(0, 5), (2, 3, 4), (1, 6)],
[(0, 5), (2, 3, 6), (1, 4)],
[(0, 5), (2, 4, 6), (1, 3)],
[(0, 5), (3, 4, 6), (1, 2)],
[(0, 6), (1, 2, 3), (4, 5)],
[(0, 6), (1, 2, 4), (3, 5)],
[(0, 6), (1, 2, 5), (3, 4)],
[(0, 6), (1, 3, 4), (2, 5)],
[(0, 6), (1, 3, 5), (2, 4)],
[(0, 6), (1, 4, 5), (2, 3)],
[(0, 6), (2, 3, 4), (1, 5)],
[(0, 6), (2, 3, 5), (1, 4)],
[(0, 6), (2, 4, 5), (1, 3)],
[(0, 6), (3, 4, 5), (1, 2)],
[(1, 2), (0, 3, 4), (5, 6)],
[(1, 2), (0, 3, 5), (4, 6)],
[(1, 2), (0, 3, 6), (4, 5)],
[(1, 2), (0, 4, 5), (3, 6)],
[(1, 2), (0, 4, 6), (3, 5)],
[(1, 2), (0, 5, 6), (3, 4)],
[(1, 2), (3, 4, 5), (0, 6)],
[(1, 2), (3, 4, 6), (0, 5)],
[(1, 2), (3, 5, 6), (0, 4)],
[(1, 2), (4, 5, 6), (0, 3)],
[(1, 3), (0, 2, 4), (5, 6)],
[(1, 3), (0, 2, 5), (4, 6)],
[(1, 3), (0, 2, 6), (4, 5)],
[(1, 3), (0, 4, 5), (2, 6)],
[(1, 3), (0, 4, 6), (2, 5)],
[(1, 3), (0, 5, 6), (2, 4)],
[(1, 3), (2, 4, 5), (0, 6)],
[(1, 3), (2, 4, 6), (0, 5)],
[(1, 3), (2, 5, 6), (0, 4)],
[(1, 3), (4, 5, 6), (0, 2)],
[(1, 4), (0, 2, 3), (5, 6)],
[(1, 4), (0, 2, 5), (3, 6)],
[(1, 4), (0, 2, 6), (3, 5)],
[(1, 4), (0, 3, 5), (2, 6)],
[(1, 4), (0, 3, 6), (2, 5)],
[(1, 4), (0, 5, 6), (2, 3)],
[(1, 4), (2, 3, 5), (0, 6)],
[(1, 4), (2, 3, 6), (0, 5)],
[(1, 4), (2, 5, 6), (0, 3)],
[(1, 4), (3, 5, 6), (0, 2)],
[(1, 5), (0, 2, 3), (4, 6)],
[(1, 5), (0, 2, 4), (3, 6)],
[(1, 5), (0, 2, 6), (3, 4)],
[(1, 5), (0, 3, 4), (2, 6)],
[(1, 5), (0, 3, 6), (2, 4)],
[(1, 5), (0, 4, 6), (2, 3)],
[(1, 5), (2, 3, 4), (0, 6)],
[(1, 5), (2, 3, 6), (0, 4)],
[(1, 5), (2, 4, 6), (0, 3)],
[(1, 5), (3, 4, 6), (0, 2)],
[(1, 6), (0, 2, 3), (4, 5)],
[(1, 6), (0, 2, 4), (3, 5)],
[(1, 6), (0, 2, 5), (3, 4)],
[(1, 6), (0, 3, 4), (2, 5)],
[(1, 6), (0, 3, 5), (2, 4)],
[(1, 6), (0, 4, 5), (2, 3)],
[(1, 6), (2, 3, 4), (0, 5)],
[(1, 6), (2, 3, 5), (0, 4)],
[(1, 6), (2, 4, 5), (0, 3)],
[(1, 6), (3, 4, 5), (0, 2)],
[(2, 3), (0, 1, 4), (5, 6)],
[(2, 3), (0, 1, 5), (4, 6)],
[(2, 3), (0, 1, 6), (4, 5)],
[(2, 3), (0, 4, 5), (1, 6)],
[(2, 3), (0, 4, 6), (1, 5)],
[(2, 3), (0, 5, 6), (1, 4)],
[(2, 3), (1, 4, 5), (0, 6)],
[(2, 3), (1, 4, 6), (0, 5)],
[(2, 3), (1, 5, 6), (0, 4)],
[(2, 3), (4, 5, 6), (0, 1)],
[(2, 4), (0, 1, 3), (5, 6)],
[(2, 4), (0, 1, 5), (3, 6)],
[(2, 4), (0, 1, 6), (3, 5)],
[(2, 4), (0, 3, 5), (1, 6)],
[(2, 4), (0, 3, 6), (1, 5)],
[(2, 4), (0, 5, 6), (1, 3)],
[(2, 4), (1, 3, 5), (0, 6)],
[(2, 4), (1, 3, 6), (0, 5)],
[(2, 4), (1, 5, 6), (0, 3)],
[(2, 4), (3, 5, 6), (0, 1)],
[(2, 5), (0, 1, 3), (4, 6)],
[(2, 5), (0, 1, 4), (3, 6)],
[(2, 5), (0, 1, 6), (3, 4)],
[(2, 5), (0, 3, 4), (1, 6)],
[(2, 5), (0, 3, 6), (1, 4)],
[(2, 5), (0, 4, 6), (1, 3)],
[(2, 5), (1, 3, 4), (0, 6)],
[(2, 5), (1, 3, 6), (0, 4)],
[(2, 5), (1, 4, 6), (0, 3)],
[(2, 5), (3, 4, 6), (0, 1)],
[(2, 6), (0, 1, 3), (4, 5)],
[(2, 6), (0, 1, 4), (3, 5)],
[(2, 6), (0, 1, 5), (3, 4)],
[(2, 6), (0, 3, 4), (1, 5)],
[(2, 6), (0, 3, 5), (1, 4)],
[(2, 6), (0, 4, 5), (1, 3)],
[(2, 6), (1, 3, 4), (0, 5)],
[(2, 6), (1, 3, 5), (0, 4)],
[(2, 6), (1, 4, 5), (0, 3)],
[(2, 6), (3, 4, 5), (0, 1)],
[(3, 4), (0, 1, 2), (5, 6)],
[(3, 4), (0, 1, 5), (2, 6)],
[(3, 4), (0, 1, 6), (2, 5)],
[(3, 4), (0, 2, 5), (1, 6)],
[(3, 4), (0, 2, 6), (1, 5)],
[(3, 4), (0, 5, 6), (1, 2)],
[(3, 4), (1, 2, 5), (0, 6)],
[(3, 4), (1, 2, 6), (0, 5)],
[(3, 4), (1, 5, 6), (0, 2)],
[(3, 4), (2, 5, 6), (0, 1)],
[(3, 5), (0, 1, 2), (4, 6)],
[(3, 5), (0, 1, 4), (2, 6)],
[(3, 5), (0, 1, 6), (2, 4)],
[(3, 5), (0, 2, 4), (1, 6)],
[(3, 5), (0, 2, 6), (1, 4)],
[(3, 5), (0, 4, 6), (1, 2)],
[(3, 5), (1, 2, 4), (0, 6)],
[(3, 5), (1, 2, 6), (0, 4)],
[(3, 5), (1, 4, 6), (0, 2)],
[(3, 5), (2, 4, 6), (0, 1)],
[(3, 6), (0, 1, 2), (4, 5)],
[(3, 6), (0, 1, 4), (2, 5)],
[(3, 6), (0, 1, 5), (2, 4)],
[(3, 6), (0, 2, 4), (1, 5)],
[(3, 6), (0, 2, 5), (1, 4)],
[(3, 6), (0, 4, 5), (1, 2)],
[(3, 6), (1, 2, 4), (0, 5)],
[(3, 6), (1, 2, 5), (0, 4)],
[(3, 6), (1, 4, 5), (0, 2)],
[(3, 6), (2, 4, 5), (0, 1)],
[(4, 5), (0, 1, 2), (3, 6)],
[(4, 5), (0, 1, 3), (2, 6)],
[(4, 5), (0, 1, 6), (2, 3)],
[(4, 5), (0, 2, 3), (1, 6)],
[(4, 5), (0, 2, 6), (1, 3)],
[(4, 5), (0, 3, 6), (1, 2)],
[(4, 5), (1, 2, 3), (0, 6)],
[(4, 5), (1, 2, 6), (0, 3)],
[(4, 5), (1, 3, 6), (0, 2)],
[(4, 5), (2, 3, 6), (0, 1)],
[(4, 6), (0, 1, 2), (3, 5)],
[(4, 6), (0, 1, 3), (2, 5)],
[(4, 6), (0, 1, 5), (2, 3)],
[(4, 6), (0, 2, 3), (1, 5)],
[(4, 6), (0, 2, 5), (1, 3)],
[(4, 6), (0, 3, 5), (1, 2)],
[(4, 6), (1, 2, 3), (0, 5)],
[(4, 6), (1, 2, 5), (0, 3)],
[(4, 6), (1, 3, 5), (0, 2)],
[(4, 6), (2, 3, 5), (0, 1)],
[(5, 6), (0, 1, 2), (3, 4)],
[(5, 6), (0, 1, 3), (2, 4)],
[(5, 6), (0, 1, 4), (2, 3)],
[(5, 6), (0, 2, 3), (1, 4)],
[(5, 6), (0, 2, 4), (1, 3)],
[(5, 6), (0, 3, 4), (1, 2)],
[(5, 6), (1, 2, 3), (0, 4)],
[(5, 6), (1, 2, 4), (0, 3)],
[(5, 6), (1, 3, 4), (0, 2)],
[(5, 6), (2, 3, 4), (0, 1)]]
Generate the permutations and remove duplicates.
>>> import itertools
>>> Na = 2
>>> Nb = 2
>>> p = itertools.permutations(['R']*Na + ['B']*Nb)
>>> for perm in sorted(list(set(p)), reverse=True):
... print perm
...
('R', 'R', 'B', 'B')
('R', 'B', 'R', 'B')
('R', 'B', 'B', 'R')
('B', 'R', 'R', 'B')
('B', 'R', 'B', 'R')
('B', 'B', 'R', 'R')
You can solve that with itertools:
import itertools
last = None
result = []
for v in itertools.permutations(['A','A','B','B']):
key = "".join(v)
if key == last: continue
last = key
result.append(v)
print result
Here is one possible way of implementing:
def permutations(colors, l):
if l == 0:
yield []
else:
for i in range(len(colors)):
if colors[i]:
la = colors[:i]
lb = [colors[i][1:]]
lc = colors[i + 1:]
choice = colors[i][0]
for rest in permutations(la + lb + lc, l - 1):
yield [choice] + rest
Usage:
for choice in permutations([['R'] * 2, ['B'] * 2], 4):
print(choice)
['R', 'R', 'B', 'B']
['R', 'B', 'R', 'B']
['R', 'B', 'B', 'R']
['B', 'R', 'R', 'B']
['B', 'R', 'B', 'R']
['B', 'B', 'R', 'R']

Categories