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')], []]

Categories

Resources