2014-09-04 9 views
5

voglio trovare tutte le possibili combinazioni del seguente elenco:tutto combinazione di un elenco complicato

data = ['a','b','c','d'] 

So che sembra un compito semplice e può essere raggiunta da qualcosa come il seguente codice:

comb = [c for i in range(1, len(data)+1) for c in combinations(data, i)] 

ma quello che voglio è in realtà un modo per assegnare a ogni elemento della lista dati due possibilità ('a' o '-a').

Un esempio delle combinazioni può essere ['a','b'], ['-a','b'], ['a','b','-c'], ecc senza qualcosa come il seguente caso, naturalmente ['-a','a'].

risposta

5

Si potrebbe scrivere una funzione generatore che prende una sequenza e produce ogni possibile combinazione di negazioni. Come questo:

import itertools 
def negations(seq): 
    for prefixes in itertools.product(["", "-"], repeat=len(seq)): 
     yield [prefix + value for prefix, value in zip(prefixes, seq)] 

print list(negations(["a", "b", "c"])) 

Risultato (spazi bianchi modificato per chiarezza):

[ 
    [ 'a', 'b', 'c'], 
    [ 'a', 'b', '-c'], 
    [ 'a', '-b', 'c'], 
    [ 'a', '-b', '-c'], 
    ['-a', 'b', 'c'], 
    ['-a', 'b', '-c'], 
    ['-a', '-b', 'c'], 
    ['-a', '-b', '-c'] 
] 

È possibile integrare questo nel codice esistente con qualcosa di simile

comb = [x for i in range(1, len(data)+1) for c in combinations(data, i) for x in negations(c)] 
+0

molte grazie, esattamente quello che voglio :) – Ophilia

3

Una volta generate le combinazioni regolari, è possibile eseguire un secondo passaggio per generare quelle con "negazione". Lo penserei come un numero binario, con il numero di elementi nella tua lista come numero di bit. Contare da 0b0000 a 0b1111 tramite 0b0001, 0b0010, ecc. E ovunque sia impostato un bit, annulla l'elemento nel risultato. Questo produrrà 2^n combinazioni per ciascuna combinazione di input di lunghezza n.

+0

grazie per il suggerimento, che è stato davvero utile – Ophilia

0

La mia soluzione fondamentalmente ha la stessa idea come John Zwinck's answer. Dopo aver prodotto la lista di tutte le combinazioni

comb = [c for i in range(1, len(data)+1) for c in combinations(data, i)] 

si generano tutte le possibili combinazioni positive/negative per ogni elemento di comb. Lo faccio ripetendo il numero totale di combinazioni, 2**(N-1), e trattandolo come un numero binario, dove ogni cifra binaria rappresenta il segno di un elemento. (Ad esempio, un elenco di due elementi avrebbe 4 combinazioni possibili, da 0 a 3, rappresentata dal 0b00 => (+,+), 0b01 => (-,+), 0b10 => (+,-) e 0b11 => (-,-).)

def twocombinations(it): 
    sign = lambda c, i: "-" if c & 2**i else "" 
    l = list(it) 

    if len(l) < 1: 
     return 

    # for each possible combination, make a tuple with the appropriate 
    # sign before each element 
    for c in range(2**(len(l) - 1)): 
     yield tuple(sign(c, i) + el for i, el in enumerate(l)) 

Ora applichiamo questa funzione per ogni elemento di comb e appiattire il conseguente annidato iteratore:

l = itertools.chain.from_iterable(map(twocombinations, comb)) 
3

Ecco one-liner, ma può essere difficile da seguire:

from itertools import product 

comb = [sum(t, []) for t in product(*[([x], ['-' + x], []) for x in data])] 

Prima mappa data alle liste di ciò che possono diventare nei risultati. Quindi prendere product* per ottenere tutte le possibilità. Infine, appiattisci ciascuna combinazione con sum.

Problemi correlati