marsx
marsx

Reputation: 715

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 already 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.

Upvotes: 7

Views: 7937

Answers (6)

Dafydd Gibbon
Dafydd Gibbon

Reputation: 1

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)]

Upvotes: 0

martineau
martineau

Reputation: 123463

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')

Upvotes: 22

Hugh Bothwell
Hugh Bothwell

Reputation: 56644

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

Upvotes: 3

Nate
Nate

Reputation: 12829

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')

Upvotes: 5

Skurmedel
Skurmedel

Reputation: 22149

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']

Upvotes: 5

João Neves
João Neves

Reputation: 957

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.

Upvotes: 2

Related Questions