python get groups of combinations that each member appear only once - python

I'm trying to get groups of permutations/combinations (r=2) that each member appear only once
I used python 'combinations' package to have the combinations.
For example: the members are: a,b,c,d.
The combinations are: [a,b],[a,c],[a,d],[b,c],[b,d]...
My desired output is:
[ {[a,b],[c,d]},{[a,c],[b,d]},{[a,d],[b,c]}...]
I would like to know what is the terminology for that case and if there is already implementation for that.
Thanks.

Here's a way to do it:
from itertools import combinations, chain
l = ['a','b','c','d']
c = list(combinations(l,2))
[set(i) for i in list(combinations(c,2)) if (len(set(l) & set(chain(*i))) == len(l))]
[{('a', 'b'), ('c', 'd')}, {('a', 'c'), ('b', 'd')}, {('a', 'd'), ('b', 'c')}]
Explanation
You can use itertools.combinations twice, in order to get all the 2 tuple combinations from:
list(combinations(l,2))
[('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
And select only those whose set of elements intersect with that of the original list, len(set(l) & set(chain(*i))) == len(l)) for every possible combination.

You can find the permutations up to r and then filter the results:
def combinations(d, d1, r, _c = [], _start=[]):
if len([i for b in _c for i in b]) == len(d1):
yield _c
else:
for i in d:
if i not in _start:
if len(_start+[i]) < r:
yield from combinations(d, d1, r, _c, _start=_start+[i])
else:
_d = sorted(_start+[i])
yield from combinations([i for i in d if i not in _d], d1,r, _c+[_d], [])
data = ['a', 'b', 'c', 'd']
_r = list(combinations(data, data, 2))
new_d = [a for i, a in enumerate(_r) if a not in _r[:i]]
Output:
[[['a', 'b'], ['c', 'd']], [['a', 'c'], ['b', 'd']], [['a', 'd'], ['b', 'c']], [['b', 'c'], ['a', 'd']], [['b', 'd'], ['a', 'c']], [['c', 'd'], ['a', 'b']]]

Related

How can I rearrange a set of values into new pattern on python and print results

so I will do my best to explain what I'm looking for,
at the moment I have a 100 item list that I want to repetitively shuffle using a set pattern to first check if the pattern will eventually bring me back to where I began
and 2 to print the result of each loop to a text file.
so using a 3 item list as my example
[a,b,c]
and the shuffle pattern [3 1 2]
where the 3rd item becomes the first.
the first item becomes the second
and the second item becomes the 3rd
on a loop would generate the following patterns
[a,b,c]
[3,1,2]
[c,a,b]
[b,c,a]
[a,b,c]
but I have a list at the moment of 100 items that I need to find every single arrangement for a few different patterns I would like to test out.
does anyone know of a way to do this in python please.
You can define function and call this function multi times like below:
>>> def func(lst, ptr):
... return [lst[idx-1] for idx in ptr]
>>> lst = ['a','b','c']
>>> ptr = [3,1,2]
>>> for _ in range(5):
... lst = func(lst, ptr)
... print(lst)
['c', 'a', 'b']
['b', 'c', 'a']
['a', 'b', 'c']
['c', 'a', 'b']
['b', 'c', 'a']
You could use numpy advanced integer indexing if your list contains a numeric type:
import numpy as np
original_list=[1,2,3]
numpy_array = np.array(original_list)
pattern = [2,1,0]
print(numpy_array[pattern])
>>> array([3, 2, 1])
def rearrange(pattern : list,L:list):
new_list = []
for i in pattern :
new_list.append(L[i-1])
return new_list
print(rearrange([3,1,2],['a','b','c']))
output :
['c', 'a', 'b']
Itertools could be what you need.
import itertools
p = itertools.permutations(['a','b','c', 'd'])
list(p)
Output:
[('a', 'b', 'c', 'd'),
('a', 'b', 'd', 'c'),
('a', 'c', 'b', 'd'),
('a', 'c', 'd', 'b'),
('a', 'd', 'b', 'c'),
('a', 'd', 'c', 'b'),
('b', 'a', 'c', 'd'),
('b', 'a', 'd', 'c'),
('b', 'c', 'a', 'd'),
('b', 'c', 'd', 'a'),
('b', 'd', 'a', 'c'),
('b', 'd', 'c', 'a'),
('c', 'a', 'b', 'd'),
('c', 'a', 'd', 'b'),
('c', 'b', 'a', 'd'),
('c', 'b', 'd', 'a'),
('c', 'd', 'a', 'b'),
('c', 'd', 'b', 'a'),
('d', 'a', 'b', 'c'),
('d', 'a', 'c', 'b'),
('d', 'b', 'a', 'c'),
('d', 'b', 'c', 'a'),
('d', 'c', 'a', 'b'),
('d', 'c', 'b', 'a')]
​

Convert Set of Tuples to a List of Lists | Python

Generating unique combinations by using set() over itertools.
Outputs a set of tuples, each originating from their invocations respectively.
Instead, I now want to convert this result into a list.
import itertools
my_list = ['A', 'B', 'C']
pairs = set(itertools.combinations(my_list, 2))
print(pairs)
>>> {('A', 'C'), ('B', 'C'), ('A', 'B')}
Instead, I would like:
[['A', 'C'], ['B', 'C'], ['A', 'B']]
a =[[item for item in pair] for pair in pairs]
print(a)
returns
[['B', 'C'], ['A', 'C'], ['A', 'B']]

How do I convert a list of pairs into a dictionary with each element as a key to a list of paired values?

I'm doing coursework which involves graphs. I have edge lists E=[('a','b'),('a','c'),('a','d'), ('b','c') etc. ] and I want to a function to convert them into adjacency matrices in the form of dictionaries {'a':['b','c','d'], 'b':['a', etc. } so that I can use a function that only inputs these dictionaries.
My main issue is I can't figure out how to use a loop to add key:values without just overwriting the lists. A previous version of my function would output [] as all values because 'f' has no connections.
I've tried this:
V = ['a','b','c','d','e','f']
E=[('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
def EdgeListtoAdjMat(V,E):
GA={}
conneclist=[]
for v in V:
for i in range(len(V)):
conneclist.append([])
if (v,V[i]) in E:
conneclist[i].append(V[i])
for i in range(len(V)):
GA[V[i]]=conneclist[i]
return(GA)
EdgeListtoAdjMat(V,E) outputs:
{'a': [], 'b': ['b'], 'c': ['c', 'c'], 'd': ['d', 'd', 'd'], 'e': [], 'f': []}
whereas it should output:
{'a':['b','c','d'],
'b':['a','c','d'],
'c':['a','b','d'],
'd':['a','b','c'],
'e':[],
'f':[]
}
The logic of what you're trying to achieve is actually quite simple:
V = ['a','b','c','d','e','f']
E=[('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
result = {}
for elem in V:
tempList = []
for item in E:
if elem in item:
if elem == item[0]:
tempList.append(item[1])
else:
tempList.append(item[0])
result[elem] = tempList
tempList = []
print(result)
Result:
{'a': ['b', 'c', 'd'], 'b': ['a', 'c', 'd'], 'c': ['a', 'b', 'd'], 'd': ['a', 'b', 'c'], 'e': [], 'f': []}
For every element in V, perform a check to see whether that element exists in any tuple in E. If it exists, then take the element that together form a pair on that tuple and append to a temporary list. After checking every element in E, update the result dictionary and move to the next element of V until you're done.
To get back to your code, you need to modify it as following:
def EdgeListtoAdjMat(V,E):
GA={}
conneclist=[]
for i in range(len(V)):
for j in range(len(V)):
# Checking if a pair of two different elements exists in either format inside E.
if not i==j and ((V[i],V[j]) in E or (V[j],V[i]) in E):
conneclist.append(V[j])
GA[V[i]]=conneclist
conneclist = []
return(GA)
A more efficient approach is to iterate through the edges and append to the output dict of lists the vertices in both directions. Use dict.setdefault to initialize each new key with a list. And when the iterations over the edges finish, iterate over the rest of the vertices that are not yet in the output dict to assign to them empty lists:
def EdgeListtoAdjMat(V,E):
GA = {}
for a, b in E:
GA.setdefault(a, []).append(b)
GA.setdefault(b, []).append(a)
for v in V:
if v not in GA:
GA[v] = []
return GA
so that given:
V = ['a', 'b', 'c', 'd', 'e', 'f']
E = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
EdgeListtoAdjMat(V, E)) would return:
{'a': ['b', 'c', 'd'], 'b': ['a', 'c', 'd'], 'c': ['a', 'b', 'd'], 'd': ['a', 'b', 'c'], 'e': [], 'f': []}
Since you already have your list of vertices in V, it is easy to prepare a dictionary with an empty list of connections. Then, simply go through the edge list and add to the array on each side:
V = ['a','b','c','d','e','f']
E = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
GA = {v:[] for v in V}
for v1,v2 in E:
GA[v1].append(v2)
GA[v2].append(v1)
I think your code is not very pythonic, you could write a more readable code that is simpler to debug and also faster since you are using python's built-in libraries and numpy's indexing.
def EdgeListToAdjMat(V, E):
AdjMat = np.zeros((len(V), len(V))) # the shape of Adjancy Matrix
connectlist = {
# Mapping each character to its index
x: idx for idx, x in enumerate(V)
}
for e in E:
v1, v2 = e
idx_1, idx_2 = connectlist[v1], connectlist[v2]
AdjMat[idx_1, idx_2] = 1
AdjMat[idx_2, idx_1] = 1
return AdjMat
If you'd consider using a library, networkx is designed for these type of network problems:
import networkx as nx
V = ['a','b','c','d','e','f']
E = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
G=nx.Graph(E)
G.add_nodes_from(V)
GA = nx.to_dict_of_lists(G)
print(GA)
# {'a': ['c', 'b', 'd'], 'c': ['a', 'b', 'd'], 'b': ['a', 'c', 'd'], 'e': [], 'd': ['a', 'c', 'b'], 'f': []}
You can convert the edge list to the map using itertools.groupby
from itertools import groupby
from operator import itemgetter
V = ['a','b','c','d','e','f']
E = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
# add edge in the other direction. E.g., for a -> b, add b -> a
nondirected_edges = E + [tuple(reversed(pair)) for pair in E]
# extract start and end vertices from an edge
v_start = itemgetter(0)
v_end = itemgetter(1)
# group edges by their starting vertex
groups = groupby(sorted(nondirected_edges), key=v_start)
# make a map from each vertex -> adjacent vertices
mapping = {vertex: list(map(v_end, edges)) for vertex, edges in groups}
# if you don't need all the vertices to be present
# and just want to be able to lookup the connected
# list of vertices to a given vertex at some point
# you can use a defaultdict:
from collections import defaultdict
adj_matrix = defaultdict(list, mapping)
# if you need all vertices present immediately:
adj_matrix = dict(mapping)
adj_matrix.update({vertex: [] for vertex in V if vertex not in mapping})

How to generate the permutation of a list in python? [duplicate]

This question already has answers here:
How do I generate all permutations of a list?
(40 answers)
Closed 8 years ago.
I am trying to generate a permutation of list in python with recursion.
import copy
def perm(seq):
if len(seq) == 1:
return seq
else:
nseq = perm(seq[1:])
return zip_letter(seq[0], nseq)
def zip_letter(c, seq):
lis = []
for i in range(len(seq)+1):
seq.insert(i, c)
lis.append(copy.deepcopy(seq))
seq.pop(i)
return lis
print perm(['a', 'b', 'c'])
The output is
[['a', ['b', 'c'], ['c', 'b']], [['b', 'c'], 'a', ['c', 'b']], [['b', 'c'], ['c', 'b'], 'a']]
which seems fine, but not in correctly inserted format.
what am i missing?
I would recommend using the existing function in itertools
>>> list(itertools.permutations(['a', 'b', 'c']))
[('a', 'b', 'c'),
('a', 'c', 'b'),
('b', 'a', 'c'),
('b', 'c', 'a'),
('c', 'a', 'b'),
('c', 'b', 'a')]

Python create many-to-many relationships from a list

I have a list, say terms = ['A', 'B', 'C', 'D']
Which is the best way to create a list-of-lists or list-of-tuples of many-to-many relationships like this;
[['A','B'],['A','C'],['A','D'],['B','C'],['B','D'],['C','D']]
Using itertools.combinations():
from itertools import combinations
list(combinations(terms, r=2))
Demo:
>>> from itertools import combinations
>>> terms = ['A', 'B', 'C', 'D']
>>> list(combinations(terms, r=2))
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]
These are tuples, not lists, but that's easily remedied if that is a problem:
>>> map(list, combinations(terms, r=2))
[['A', 'B'], ['A', 'C'], ['A', 'D'], ['B', 'C'], ['B', 'D'], ['C', 'D']]

Categories