Python permutations of both sequence and subsequences - python
Question: How do I implement double_permutations(s) below?
>>> s = [('a', 'b'), ('c', 'd'), ('e', 'f')]
>>> for answer in double_permutation(s):
... print(answer) # in some order
[('a', 'b'), ('c', 'd'), ('e', 'f')]
[('a', 'b'), ('d', 'c'), ('e', 'f')]
[('a', 'b'), ('c', 'd'), ('f', 'e')]
[('a', 'b'), ('d', 'c'), ('f', 'e')]
[('a', 'b'), ('e', 'f'), ('c', 'd')]
[('a', 'b'), ('f', 'e'), ('c', 'd')]
[('a', 'b'), ('e', 'f'), ('d', 'c')]
[('a', 'b'), ('f', 'e'), ('d', 'c')]
What I've tried (breaks down once the outer list is longer than 3 elements)
from itertools import permutations
def double_permutation(l):
def double_permutation_recur(s, r):
if not r:
yield s
else:
for permutation in permutations(r):
s1 = s + [permutation[0]]
s2 = s + [(permutation[0][1], permutation[0][0])]
for perm1 in double_permutation_recur(s1, permutation[1:]):
yield perm1
for perm2 in double_permutation_recur(s2, permutation[1:]):
yield perm2
return double_permutation_recur([l[0]], l[1:])
This should yield double_factorial(n-1) answers for a list of length n. This works up through n = 3, but breaks down at n = 4 (which yields 96 instead of 48 answers).
You can build this up from the primitives in the itertools module
import itertools
s = [('a', 'b'), ('c', 'd'), ('e', 'f')]
Is this what you're describing?
def permute(it):
return itertools.product(*(itertools.permutations(i) for i in it))
>>> for i in permute(s):
... print i
(('a', 'b'), ('c', 'd'), ('e', 'f'))
(('a', 'b'), ('c', 'd'), ('f', 'e'))
(('a', 'b'), ('d', 'c'), ('e', 'f'))
(('a', 'b'), ('d', 'c'), ('f', 'e'))
(('b', 'a'), ('c', 'd'), ('e', 'f'))
(('b', 'a'), ('c', 'd'), ('f', 'e'))
(('b', 'a'), ('d', 'c'), ('e', 'f'))
(('b', 'a'), ('d', 'c'), ('f', 'e'))
Or do you want:
def permute2(it):
return itertools.chain.from_iterable(
permute(p)
for p in itertools.permutations(it)
)
>>> for i in permute2(s):
... print i
(('a', 'b'), ('c', 'd'), ('e', 'f'))
(('a', 'b'), ('c', 'd'), ('f', 'e'))
(('a', 'b'), ('d', 'c'), ('e', 'f'))
(('a', 'b'), ('d', 'c'), ('f', 'e'))
(('b', 'a'), ('c', 'd'), ('e', 'f'))
(('b', 'a'), ('c', 'd'), ('f', 'e'))
(('b', 'a'), ('d', 'c'), ('e', 'f'))
(('b', 'a'), ('d', 'c'), ('f', 'e'))
(('a', 'b'), ('e', 'f'), ('c', 'd'))
(('a', 'b'), ('e', 'f'), ('d', 'c'))
(('a', 'b'), ('f', 'e'), ('c', 'd'))
(('a', 'b'), ('f', 'e'), ('d', 'c'))
(('b', 'a'), ('e', 'f'), ('c', 'd'))
(('b', 'a'), ('e', 'f'), ('d', 'c'))
(('b', 'a'), ('f', 'e'), ('c', 'd'))
(('b', 'a'), ('f', 'e'), ('d', 'c'))
(('c', 'd'), ('a', 'b'), ('e', 'f'))
(('c', 'd'), ('a', 'b'), ('f', 'e'))
(('c', 'd'), ('b', 'a'), ('e', 'f'))
(('c', 'd'), ('b', 'a'), ('f', 'e'))
(('d', 'c'), ('a', 'b'), ('e', 'f'))
(('d', 'c'), ('a', 'b'), ('f', 'e'))
(('d', 'c'), ('b', 'a'), ('e', 'f'))
(('d', 'c'), ('b', 'a'), ('f', 'e'))
(('c', 'd'), ('e', 'f'), ('a', 'b'))
(('c', 'd'), ('e', 'f'), ('b', 'a'))
(('c', 'd'), ('f', 'e'), ('a', 'b'))
(('c', 'd'), ('f', 'e'), ('b', 'a'))
(('d', 'c'), ('e', 'f'), ('a', 'b'))
(('d', 'c'), ('e', 'f'), ('b', 'a'))
(('d', 'c'), ('f', 'e'), ('a', 'b'))
(('d', 'c'), ('f', 'e'), ('b', 'a'))
(('e', 'f'), ('a', 'b'), ('c', 'd'))
(('e', 'f'), ('a', 'b'), ('d', 'c'))
(('e', 'f'), ('b', 'a'), ('c', 'd'))
(('e', 'f'), ('b', 'a'), ('d', 'c'))
(('f', 'e'), ('a', 'b'), ('c', 'd'))
(('f', 'e'), ('a', 'b'), ('d', 'c'))
(('f', 'e'), ('b', 'a'), ('c', 'd'))
(('f', 'e'), ('b', 'a'), ('d', 'c'))
(('e', 'f'), ('c', 'd'), ('a', 'b'))
(('e', 'f'), ('c', 'd'), ('b', 'a'))
(('e', 'f'), ('d', 'c'), ('a', 'b'))
(('e', 'f'), ('d', 'c'), ('b', 'a'))
(('f', 'e'), ('c', 'd'), ('a', 'b'))
(('f', 'e'), ('c', 'd'), ('b', 'a'))
(('f', 'e'), ('d', 'c'), ('a', 'b'))
(('f', 'e'), ('d', 'c'), ('b', 'a'))
Or to "anchor" the first element:
def permute3(s):
return s[:1] + list(p) for p in permute2(s[1:])
>>> for i in permute3(s):
... print i
[('a', 'b'), ('c', 'd'), ('e', 'f')]
[('a', 'b'), ('c', 'd'), ('f', 'e')]
[('a', 'b'), ('d', 'c'), ('e', 'f')]
[('a', 'b'), ('d', 'c'), ('f', 'e')]
[('a', 'b'), ('e', 'f'), ('c', 'd')]
[('a', 'b'), ('e', 'f'), ('d', 'c')]
[('a', 'b'), ('f', 'e'), ('c', 'd')]
[('a', 'b'), ('f', 'e'), ('d', 'c')]
Related
Hub and Authority scores: networkx vs igraph
I computed hub and authority scores of a simple graph using igraph and networkx and they give me the same results. For example, see below import networkx as nx from igraph import * G = nx.DiGraph() G.add_edges_from([('A', 'D'), ('B', 'C'), ('B', 'E'), ('C', 'A'), ('D', 'C'), ('E', 'D'), ('E', 'B'), ('E', 'F'), ('E', 'C'), ('F', 'C'), ('F', 'H'), ('G', 'A'), ('G', 'C'), ('H', 'A')]) hubs, authorities = nx.hits(G, max_iter = 50, normalized = True) edges = [('A', 'D'), ('B', 'C'), ('B', 'E'), ('C', 'A'), ('D', 'C'), ('E', 'D'), ('E', 'B'), ('E', 'F'), ('E', 'C'), ('F', 'C'), ('F', 'H'), ('G', 'A'), ('G', 'C'), ('H', 'A')] g = Graph.TupleList(directed=True,edges=edges) hub_igraph = [g.hub_score()[i]/sum(g.hub_score()) for i in range(len(g.hub_score()))] In[1] print(hubs) Out[1] {'A': 0.04642540386472174, 'D': 0.133660375232863, 'B': 0.15763599440595596, 'C': 0.037389132480584515, 'E': 0.2588144594158868, 'F': 0.15763599440595596, 'H': 0.037389132480584515, 'G': 0.17104950771344754} In[2] print(hub_igraph) Out[2] [0.04642540403219994, 0.13366037526115376, 0.1576359944296732, 0.03738913224642651, 0.2588144598468665, 0.1576359944296732, 0.037389132246426524, 0.17104950750758036] However, for large graph (2k nodes) that is sparse and almost tree-like, the result is vastly different. I computed the hub/authority score using HITS algorithm and the output for the large graph matches the one from networkx but not the one from igraph. I cannot find the source-code for igraph and hence I am wondering where is the discrepancy coming from. Any hint is appreciated. Thanks.
how can I fix this Towers of Hanoi program for my desired output?
def moveTower(height,fromPole, toPole, withPole): if height >= 1: moveTower(height-1,fromPole,withPole,toPole) moveDisk(fromPole,toPole) moveTower(height-1,withPole,toPole,fromPole) def moveDisk(fp,tp): print("("+fp + "," +tp+')') moveTower(4,"A","B","C") I need the output to be a list of tuples (ex: [('A','C'),('A','B'), ...]) Current output: (A,C) (A,B) (C,B) (A,C) (B,A) (B,C) (A,C) (A,B) (C,B) (C,A) (B,A) (C,B) (A,C) (A,B) (C,B)
You should not print the elements. Probably the most elegant is here to construct a generator: def moveTower(height,fromPole, toPole, withPole): if height >= 1: yield from moveTower(height-1,fromPole,withPole,toPole) yield (fromPole, toPole) yield from moveTower(height-1,withPole,toPole,fromPole) yield <expr> here thus emits the value that is constructed by the <expr> in a generator, and yield from <iterable> is used to emit all elements from the <iterable> as elements of this generator. We can then use list(..) to materialize the generator: >>> list(moveTower(2, *'ABC')) [('A', 'C'), ('A', 'B'), ('C', 'B')] >>> list(moveTower(3, *'ABC')) [('A', 'B'), ('A', 'C'), ('B', 'C'), ('A', 'B'), ('C', 'A'), ('C', 'B'), ('A', 'B')] >>> list(moveTower(4, *'ABC')) [('A', 'C'), ('A', 'B'), ('C', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('A', 'C'), ('A', 'B'), ('C', 'B'), ('C', 'A'), ('B', 'A'), ('C', 'B'), ('A', 'C'), ('A', 'B'), ('C', 'B')]
The simplest modification to your code would be to append them to a list: result = [] def moveTower(height,fromPole, toPole, withPole): if height >= 1: moveTower(height-1,fromPole,withPole,toPole) moveDisk(fromPole,toPole) moveTower(height-1,withPole,toPole,fromPole) def moveDisk(fp,tp): result.append((fp,tp)) moveTower(4,"A","B","C") print(result) Output: [('A', 'C'), ('A', 'B'), ('C', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('A', 'C'), ('A', 'B'), ('C', 'B'), ('C', 'A'), ('B', 'A'), ('C', 'B'), ('A', 'C'), ('A', 'B'), ('C', 'B')]
Extract values from list and make tuples
I need a simple thing but I cannot do it: list = 'SBEDFG' I need as output: [(S,B),(B,E),(E,D),(D,F),(F,G)] This is what I tried: [(list[ind],list[ind+1]) for ind,i in list] But it gives me this error: ValueError: need more than 1 value to unpack Can you help me? Thanks!
You can simply use zip() function like this: >>>l = 'SBEDFG' >>>zip(l,l[1:]) [('S', 'B'), ('B', 'E'), ('E', 'D'), ('D', 'F'), ('F', 'G')] With Python 3.X you'll need to convert the zip result to a list: #Python 3.X >>>l = 'SBEDFG' >>>list(zip(l,l[1:])) [('S', 'B'), ('B', 'E'), ('E', 'D'), ('D', 'F'), ('F', 'G')] With list comprehension I would do it with range() function: >>>[(l[i],l[i+1]) for i in range(len(l)-1)] [('S', 'B'), ('B', 'E'), ('E', 'D'), ('D', 'F'), ('F', 'G')] Hope this helps!
try this >>> [(list[i-1], list[i]) for i in range(1, len(list))] [('S', 'B'), ('B', 'E'), ('E', 'D'), ('D', 'F'), ('F', 'G')]
>>>b=[] >>> for ind,i in enumerate(list): ... if ind < len(list)-1: ... b.append((list[ind],list[ind+1])) ... >>> print b [('S', 'B'), ('B', 'E'), ('E', 'D'), ('D', 'F'), ('F', 'G')]
Permutation with redundant overlaps? Python
I used itertools to run a permutation on a list that I have. mylist = [a, b, c, d, e, f] mypermutations = itertools.permutations(mylist,2) mypermutations_list = list(mypermutations) print mypermutations_list prints: [(a, b), (a, c), (a, d)...] However, the permutation list doesn't include (a, a), (b, b), etc. I recognize that's probably because most people don't want such redundant pairings. However, I would like to include such pairings as a control for the program I'm writing. Is there a way to run a permutation and get these combinations? I have no idea what to use instead of permutations.
You want itertools.product instead: >>> import itertools >>> mylist = ['a', 'b', 'c', 'd', 'e', 'f'] >>> list(itertools.product(mylist, repeat=2)) [('a', 'a'), ('a', 'b'), ('a', 'c'), ...]
You're looking for itertools.product, it returns the Cartesian product of the iterable: >>> from itertools import product >>> list(product('abcdef', repeat=2)) [('a', 'a'), ('a', 'b'), ('a', 'c'), ('a', 'd'), ('a', 'e'), ('a', 'f'), ('b', 'a'), ('b', 'b'), ('b', 'c'), ('b', 'd'), ('b', 'e'), ('b', 'f'), ('c', 'a'), ('c', 'b'), ('c', 'c'), ('c', 'd'), ('c', 'e'), ('c', 'f'), ('d', 'a'), ('d', 'b'), ('d', 'c'), ('d', 'd'), ('d', 'e'), ('d', 'f'), ('e', 'a'), ('e', 'b'), ('e', 'c'), ('e', 'd'), ('e', 'e'), ('e', 'f'), ('f', 'a'), ('f', 'b'), ('f', 'c'), ('f', 'd'), ('f', 'e'), ('f', 'f')]
From a combination, get subsets with members containing the same first element, python
Suppose I have the following list: ls = ['a', 'b', 'c', 'd'] I get a combination using list(itertools.combinations(iterable, 2)) >>> [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')] What I'd like to do is break this combination into subsets, such that the first member of each tuple in the subset is the same: subset1: [('a', 'b'), ('a', 'c'), ('a', 'd')] subset2: [('b', 'c'), ('b', 'd'), subset3: [('c', 'd')] Any ideas?
>>> import itertools as it >>> ls = ['a', 'b', 'c', 'd'] >>> ii=it.groupby( it.combinations(ls, 2), lambda x: x[0] ) >>> for key, iterator in ii: ... print key, list(iterator) ... a [('a', 'b'), ('a', 'c'), ('a', 'd')] b [('b', 'c'), ('b', 'd')] c [('c', 'd')] If you don't like lambda, you could use operator.itemgetter(0) instead of lambda x: x[0].
subset = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')] subsets = [[x for x in subset where x[0] == y] for y in ['a','b','c']]
try this: [filter(lambda k:k[0]==p,comb) for p in ls] where: ls = ['a', 'b', 'c', 'd'] comb = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')] the output is: [[('a', 'b'), ('a', 'c'), ('a', 'd')], [('b', 'c'), ('b', 'd')], [('c', 'd')], []]