开发者

getting every possible combination in a list

suppose I had something like this:

L1=['cat', 'dog', 'fish', 'rabbit', 'horse', 'bird', 'frog', 'mouse'...]

for x in L1:
    input1= open('file_%s'%(x), 'r')
    file1= pickle.load(input1)
    for x in L1:
        input2= open('file_%s'%(x), 'r')
        file2= pickle.load(input2)

and I wanted to get every combination of files without repeating combinations that have alr开发者_StackOverfloweady been done (once cat_dog is done do not do dog_cat again). Is there a way I could do this? My real list is in alphabetical order, if that makes any difference.


In reality what you're asking how to do is produce all combinations of two items taken in the list of names (as opposed to all the possible combination of them).

That means you can use the built-in itertools.combinations() generator function to easily (and efficiently) generate pairs of the names you want with no repeats:

L1 = ['cat', 'dog', 'fish', 'rabbit', 'horse', 'bird', 'frog', 'mouse']

for pair in combinations(L1, 2):
    print(pair)
    input1 = open('file_%s' % pair[0], 'r')
    input2 = open('file_%s' % pair[1], 'r')

Pairs processed:

('cat', 'dog')
('cat', 'fish')
('cat', 'rabbit')
('cat', 'horse')
('cat', 'bird')
('cat', 'frog')
('cat', 'mouse')
('dog', 'fish')
('dog', 'rabbit')
('dog', 'horse')
('dog', 'bird')
('dog', 'frog')
('dog', 'mouse')
('fish', 'rabbit')
('fish', 'horse')
('fish', 'bird')
('fish', 'frog')
('fish', 'mouse')
('rabbit', 'horse')
('rabbit', 'bird')
('rabbit', 'frog')
('rabbit', 'mouse')
('horse', 'bird')
('horse', 'frog')
('horse', 'mouse')
('bird', 'frog')
('bird', 'mouse')
('frog', 'mouse')


you can also do it as a generator:

L1=['cat', 'dog', 'fish', 'rabbit', 'horse', 'bird', 'frog', 'mouse']
tuples = [(x,y) for x in L1 for y in L1 if x != y]
for entry in tuples:
    if (entry[1], entry[0]) in tuples:
        tuples.remove((entry[1],entry[0]))
for pair in tuples:
    input1= open('file_%s'%(pair[0]), 'r')
    file1= pickle.load(input1)
    input2= open('file_%s'%(pair[1]), 'r')
    file2= pickle.load(input2)

After the first loop, the contents of tuples is:

('cat', 'dog')
('cat', 'fish')
('cat', 'rabbit')
('cat', 'horse')
('cat', 'bird')
('cat', 'frog')
('cat', 'mouse')
('dog', 'fish')
('dog', 'rabbit')
('dog', 'horse')
('dog', 'bird')
('dog', 'frog')
('dog', 'mouse')
('fish', 'rabbit')
('fish', 'horse')
('fish', 'bird')
('fish', 'frog')
('fish', 'mouse')
('rabbit', 'horse')
('rabbit', 'bird')
('rabbit', 'frog')
('rabbit', 'mouse')
('horse', 'bird')
('horse', 'frog')
('horse', 'mouse')
('bird', 'frog')
('bird', 'mouse')
('frog', 'mouse')


How about itertools.combinations?

Usage example:

>>> list(itertools.combinations([1, 2, 3, 4, 5, 6], 2))
[(1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 3), (2, 4), (2, 5), (2, 6), (3, 4),
(3, 5), (3, 6), (4, 5), (4, 6), (5, 6)]

First argument is an iterable, second is r, length of subsequences returned.

You can then concatenate the results with ease using map or a comprehension:

map(lambda x: x[0] + "_" + x[1], itertools.combinations(["cat", "dog", "fish"], 2)))

x in the lambda is a r-sized tuple.

Result of the above would be:

['cat_dog', 'cat_fish', 'dog_fish']


import itertools
import cPickle

def unique_pairs(lst):
    return itertools.combinations(lst, 2)

FNAME = "file_{0}".format
def load_pickle(fname):
    with open(fname) as inf:
        return cPickle.load(inf)

def naive_method(lst):
    # load each file every time it is requested
    for x,y in unique_pairs(lst):
        input1 = load_pickle(FNAME(x))
        input2 = load_pickle(FNAME(y))
        # do something with input1 and input2

def better_method(lst):
    # if you have enough memory for it!
    dat = [load_pickle(FNAME(i)) for i in lst]
    for x,y in unique_pairs(range(len(lst))):
        input1 = dat[x]
        input2 = dat[y]
        # do something with input1 and input2


There's itertools that can perform combinations and permutations (you'd want the former). As far as I can tell, you can't really specify the output format, so you'd get "catdog" as output, but the doc page gives you an idea of how the combinations function works, so you can adapt it to build what you need.


An alternative for combination creation, with no module import. Similar to @Nate's answer, but marginally less complex, creating a copy with single items and reducing on the fly (rather than generating a list of pairs and reducing by list search):

L1 = ['cat', 'dog', 'fish', 'rabbit', 'horse', 'bird', 'frog', 'mouse']
Laux = L1[:]

pairs = []
for a in L1:
    Laux.remove(a)
    for b in Laux:
        pairs += [(a,b)]
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜