2016-09-17 1 views
1

Angenommen, ich habe eine Python-Liste, die wie folgt aussieht:Python Kombinationen

[1, 2, 3, 4] 

Ich möchte in der Lage sein, eine Liste von Listen zurückzukehren alle Kombinationen von zwei oder mehr Zahlen enthält. Die Reihenfolge der Werte spielt keine Rolle, 1,2 ist das Gleiche wie 2,1. Ich möchte auch eine andere Liste zurückgeben, die die Werte enthält, die nicht in jeder Kombination enthalten sind. Zum Beispiel:

Combination 1,2/Remainder 3,4 
Combination 2,3/Remainder 1,4 
Combination 1,2,3/Remainder 4 
Combination 1,2,3,4/ Remainder - 

Die zurückgegebenen Listen für die oben würden

combination = [[1,2], [2,3], [1,2,3], [1,2,3,4]] 
remainder = [[3,4], [1,4], [4], []] 

sein habe ich nur ein paar Beispiele gezeigt ...

ich, dass der erste Teil realisieren kann wahrscheinlich erreicht werden mit itertools.combinations aber wie kann ich die Werte, die nicht in der Kombination ohne Schleife verwendet werden, zurückgeben?

Antwort

2

Aufbauend auf der Idee von Nunzio, sondern Zahlen in einem bestimmten Bereich auf binäre der Umwandlung, können Sie einfach itertools.product verwenden, um alle Kombinationen zu erhalten von 1 und 0 (oder True und False) und dann diese als eine Maske zum Filtern der "Ins" und "Outs" verwenden.

>>> lst = [1,2,3] 
>>> products = list(product([1,0], repeat=len(lst))) 
>>> [[lst[i] for i, e in enumerate(p) if e] for p in products] 
[[1, 2, 3], [1, 2], [1, 3], [1], [2, 3], [2], [3], []] 
>>> [[lst[i] for i, e in enumerate(p) if not e] for p in products] 
[[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]] 

Sie können auch eine Funktion für das enumerate Verständnis definieren und beide Teile in einem Rutsch tun:

>>> mask = lambda lst, p, v: [lst[i] for i, e in enumerate(p) if e == v] 
>>> [(mask(lst, p, 1), mask(lst, p, 0)) for p in product([1,0], repeat=len(lst))] 
[([1, 2, 3], []), 
([1, 2], [3]), 
([1, 3], [2]), 
([1], [2, 3]), 
([2, 3], [1]), 
([2], [1, 3]), 
([3], [1, 2]), 
([], [1, 2, 3])] 

Wenn Sie nur Kombinationen mit 2 oder mehr in der „in“ Liste möchten, können Sie fügen Sie eine Bedingung:

>>> [(mask(lst, p, 1), mask(lst, p, 0)) for p in product([1,0],repeat=len(lst)) if sum(p) >= 2] 

Oder numpy Arrays verwenden und die Verwendung von numpy ‚s erweiterte Indizierung machen:

>>> arr = np.array([1,2,3]) 
>>> [(arr[p==1], arr[p==0]) for p in map(np.array, product([1,0], repeat=len(arr)))] 
[(array([1, 2, 3]), array([])), 
(array([1, 2]), array([3])), 
(array([1, 3]), array([2])), 
(array([1]), array([2, 3])), 
(array([2, 3]), array([1])), 
(array([2]), array([1, 3])), 
(array([3]), array([1, 2])), 
(array([]), array([1, 2, 3]))] 
+0

wirklich nette Umsetzung !!! –

+0

Ich liebe diese Lösung! Funktioniert wie ein Traum! Vielen Dank – Mark

2

Sie können die eingestellte Differenz nehmen:

l = set([1, 2, 3, 4]) 

for i in range(len(l)+1): 
    for comb in itertools.combinations(l, i): 
     print(comb, l.difference(comb)) 

() {1, 2, 3, 4} 
(1,) {2, 3, 4} 
(2,) {1, 3, 4} 
(3,) {1, 2, 4} 
(4,) {1, 2, 3} 
(1, 2) {3, 4} 
(1, 3) {2, 4} 
(1, 4) {2, 3} 
(2, 3) {1, 4} 
(2, 4) {1, 3} 
(3, 4) {1, 2} 
(1, 2, 3) {4} 
(1, 2, 4) {3} 
(1, 3, 4) {2} 
(2, 3, 4) {1} 
(1, 2, 3, 4) set() 
+0

Beachten Sie, dass die eingestellte Differenz nur funktioniert, wenn die Liste keine Duplikate enthält. –

1

Angenommen, Sie diesen Vektor haben [1 6 3]

Sie können alle Zahlen von 0 erzeugen bis 2^3-1 wobei 3 len([1 6 3])

0 
1 
2 
3 
4 
5 
6 
7 

Nachdem Sie diese Zahlen in binäre umwandeln kann:

0 0 0 
0 0 1 
0 1 0 
0 1 1 
1 0 0 
1 0 1 
1 1 0 
1 1 1 

Legen Sie Ihren Vektor an der Oberseite der Sequenz erzeugt:

[1 6 3] 
0 0 0 
0 0 1 
0 1 0 
0 1 1 
1 0 0 
1 0 1 
1 1 0 
1 1 1 

für jede Zeile in Kombination append die Nummer, das in der gleichen Position der 1s und im Rest dass ein, die in der Lage ist, von die 0s.

so zum Beispiel Blick auf die 4. Zeile:

Combination: [6,3] 
Remainder: [1] 

Am Ende:

Combination: [],[3],[6],[6,3],[1],[1,3],[1,6],[1,6,3] 
Remainder: [1,6,3],[1,3],[1],[6,3],[6],[3],[] 

Hier ist der Code:

vec=[1,3,6] 
binary_vec = [format(i,'b').zfill(len(vec)) for i in range(2**len(vec))] 
print([[vec[i] for i,y in enumerate(x) if y != "0"] for x in binary_vec]) 
print([[vec[i] for i,y in enumerate(x) if y == "0"] for x in binary_vec]) 

Ausgang:

enter image description here

auch einen Blick auf meine Antwort in diesem Beitrag:

Determine list of all possible products from a list of integers in Python

+0

Interessanter Ansatz. Könnten Sie auch dafür einen Code bereitstellen? Sie können auch 'itertools.product ([True, False], repeat = 3)' 'anstelle von binary verwenden. –

+0

@tobias_k Vielen Dank! Ich kannte diese Funktion nicht: itertools.product ([True, False], repeat = 3)! Ich habe auch den Code zur Verfügung gestellt. –

Verwandte Themen