получать все возможные комбинации в списке - PullRequest
7 голосов
/ 24 февраля 2011

предположим, что у меня было что-то вроде этого:

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)

, и я хотел получить каждую комбинацию файлов без повторения уже выполненных комбинаций (после того, как cat_dog будет выполнен, больше не делайте dog_cat).Есть ли способ, которым я мог бы сделать это?Мой настоящий список в алфавитном порядке, если это имеет какое-либо значение.

Ответы [ 6 ]

22 голосов
/ 24 февраля 2011

На самом деле вы спрашиваете, как сделать, чтобы получить все комбинации двух элементов, взятых в списке имен (в отличие от всех возможных комбинаций их).

Это означает, что вы можете использовать встроенную функцию генератора itertools.combinations(), чтобы легко (и эффективно) генерировать пары имен, которые вы хотите, без повторов:

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

Обработано пар:

('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')
5 голосов
/ 24 февраля 2011

вы также можете сделать это как генератор:

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)

После первого цикла содержимое tuples будет равно:

('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')
5 голосов
/ 24 февраля 2011

Как насчет itertools.combination ?

Пример использования:

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

Первый аргумент является итеративным, второй - r, длина возвращаемых подпоследовательностей.

Затем можно с легкостью объединить результаты, используя карту или понимание:

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

x в лямбда-выражении - это кортеж r.

Результатом вышесказанного будет:

['cat_dog', 'cat_fish', 'dog_fish']
3 голосов
/ 24 февраля 2011
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
2 голосов
/ 24 февраля 2011

Есть itertools , которые могут выполнять комбинации и перестановки (вам нужно первое). Насколько я могу судить, вы на самом деле не можете указать формат вывода, поэтому вы получите «catdog» в качестве вывода, но страница документа дает вам представление о том, как работает функция комбинаций, так что вы можете адаптировать ее для построения что тебе нужно.

0 голосов
/ 30 января 2018

Альтернатива для создания комбинации, без импорта модуля.Подобно ответу @ Nate, но несколько менее сложным, создание копии с отдельными элементами и сокращение на лету (вместо создания списка пар и сокращения с помощью поиска по списку):

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