Reputation: 1292
In python, I have a dictionary like this...
pleio = {'firstLine': {'enf1': ['54', 'set'],
'enf2': ['48', 'free'],
'enf3': ['34', 'set'],
'enf4': ['12', 'free']}
'secondLine':{'enf5': ['56','bgb']
'enf6': ['67','kiol']
'enf7': ['11','dewd']
'enf8': ['464','cona']}}
I would like to make paired combinations with no repetition of the elements in the inner dictionary, to end up with a result like this...
{'enf3': ['34', 'set'], 'enf2': ['48', 'free']}
{'enf3': ['34', 'set'], 'enf1': ['54', 'set']}
{'enf3': ['34', 'set'], 'enf4': ['12', 'free']}
{'enf2': ['48', 'free'], 'enf1': ['54', 'set']}
{'enf2': ['48', 'free'], 'enf4': ['12', 'free']}
{'enf1': ['54', 'set'], 'enf4': ['12', 'free']}
I built a function which lets me do it...
import itertools
def pairwise():
'''
'''
leti=[]
for snp, enfs in pleio.items():
for x in itertools.combinations(enfs, 2 ):
leti.append(x)
pleopairs=[]
for i in leti:
pipi={}
for c in i:
pipi[c]= enfs[c]
pleopairs.append(pipi)
..but i was wondering if there's a more efficient way, like another specific function from itertools, or any other source. By the way, I found a function called "pairwise" in the itertools documentation. But I don't know how to adapt it, if would be possible in my case, or improve my attempt. Any help?
Upvotes: 2
Views: 1736
Reputation: 1125138
Your combinations
approach was correct, you just need to turn the results of each combination into a dict again:
import itertools
def pairwise(input):
for values in input.itervalues():
for pair in itertools.combinations(values.iteritems(), 2):
yield dict(pair)
This version is a generator, yielding pairs efficiently, nothing is held in memory any longer than absolutely necessary. If you need a list, just call list()
on the generator:
list(pairwise(pleio))
Output:
>>> from pprint import pprint
>>> pprint(list(pairwise(pleio)))
[{'enf2': ['48', 'free'], 'enf3': ['34', 'set']},
{'enf1': ['54', 'set'], 'enf3': ['34', 'set']},
{'enf3': ['34', 'set'], 'enf4': ['12', 'free']},
{'enf1': ['54', 'set'], 'enf2': ['48', 'free']},
{'enf2': ['48', 'free'], 'enf4': ['12', 'free']},
{'enf1': ['54', 'set'], 'enf4': ['12', 'free']}]
You can even combine the whole thing into a one-liner generator:
from itertools import combinations
for paired in (dict(p) for v in pleio.itervalues() for p in combinations(v.iteritems(), 2)):
print paired
Which outputs:
>>> for paired in (dict(p) for v in pleio.itervalues() for p in combinations(v.iteritems(), 2)):
... print paired
...
{'enf3': ['34', 'set'], 'enf2': ['48', 'free']}
{'enf3': ['34', 'set'], 'enf1': ['54', 'set']}
{'enf3': ['34', 'set'], 'enf4': ['12', 'free']}
{'enf2': ['48', 'free'], 'enf1': ['54', 'set']}
{'enf2': ['48', 'free'], 'enf4': ['12', 'free']}
{'enf1': ['54', 'set'], 'enf4': ['12', 'free']}
If you are on Python 3, replace .itervalues()
and .iteritems()
by .values()
and .items()
respectively.
Upvotes: 4
Reputation: 2250
If you want all pair combinations, you could probably use the following which is shorter, but I would not say this is more efficient.
[dict([(x,vx),(y,vy)]) for (x,vx) in pleio['firstLine'].iteritems()
for (y,vy) in pleio['firstLine'].iteritems()
if x < y]
Output
[{'enf3': ['34', 'set'], 'enf4': ['12', 'free']},
{'enf2': ['48', 'free'], 'enf3': ['34', 'set']},
{'enf2': ['48', 'free'], 'enf4': ['12', 'free']},
{'enf1': ['54', 'set'], 'enf3': ['34', 'set']},
{'enf1': ['54', 'set'], 'enf2': ['48', 'free']},
{'enf1': ['54', 'set'], 'enf4': ['12', 'free']}]
Upvotes: 1