web-dev-qa-db-fra.com

Trouver toutes les combinaisons d'une liste de nombres avec une somme donnée

J'ai une liste de numéros, par ex.

numbers = [1, 2, 3, 7, 7, 9, 10]

Comme vous pouvez le voir, les chiffres peuvent apparaître plusieurs fois dans cette liste.

J'ai besoin d'obtenir toutes les combinaisons de ces nombres qui ont une somme donnée, par exemple 10.

Les éléments des combinaisons ne peuvent pas être répétés, mais chaque élément de numbers doit être traité de manière unique, cela signifie par exemple les deux 7 dans la liste représentent différents éléments avec la même valeur.

L'ordre est sans importance, de sorte que [1, 9] et [9, 1] sont la même combinaison.

Il n'y a aucune restriction de longueur pour les combinaisons, [10] est aussi valide que [1, 2, 7].

Comment puis-je créer une liste de toutes les combinaisons répondant aux critères ci-dessus?

Dans cet exemple, ce serait [[1,2,7], [1,2,7], [1,9], [3,7], [3,7], [10]]

10
Byte Commander

Vous pouvez utiliser itertools pour parcourir toutes les combinaisons de toutes les tailles possibles et filtrer tout ce qui ne correspond pas à 10:

import itertools
numbers = [1, 2, 3, 7, 7, 9, 10]
result = [seq for i in range(len(numbers), 0, -1) for seq in itertools.combinations(numbers, i) if sum(seq) == 10]
print result

Résultat:

[(1, 2, 7), (1, 2, 7), (1, 9), (3, 7), (3, 7), (10,)]

Malheureusement, c'est quelque chose comme la complexité O (2 ^ N), donc il ne convient pas pour des listes d'entrée plus grandes, disons, 20 éléments.

16
Kevin

La solution proposée par @kgoodrick est géniale mais je pense qu'elle est plus utile en tant que générateur:

def subset_sum(numbers, target, partial=[], partial_sum=0):
    if partial_sum == target:
        yield partial
    if partial_sum >= target:
        return
    for i, n in enumerate(numbers):
        remaining = numbers[i + 1:]
        yield from subset_sum(remaining, target, partial + [n], partial_sum + n)

list(subset_sum([1, 2, 3, 7, 7, 9, 10], 10)) donne [[1, 2, 7], [1, 2, 7], [1, 9], [3, 7], [3, 7], [10]].

11
Martin Valgur

Cette question a été posée auparavant, voir la réponse @msalvadores ici . J'ai mis à jour le code python donné pour s'exécuter dans python 3:

def subset_sum(numbers, target, partial=[]):
    s = sum(partial)

    # check if the partial sum is equals to target
    if s == target:
        print("sum(%s)=%s" % (partial, target))
    if s >= target:
        return  # if we reach the number why bother to continue

    for i in range(len(numbers)):
        n = numbers[i]
        remaining = numbers[i + 1:]
        subset_sum(remaining, target, partial + [n])


if __name__ == "__main__":
    subset_sum([3, 3, 9, 8, 4, 5, 7, 10], 15)

    # Outputs:
    # sum([3, 8, 4])=15
    # sum([3, 5, 7])=15
    # sum([8, 7])=15
    # sum([5, 10])=15
7
kgoodrick

Cela marche...

from itertools import combinations


def SumTheList(thelist, target):
    arr = []
    p = []    
    if len(thelist) > 0:
        for r in range(0,len(thelist)+1):        
            arr += list(combinations(thelist, r))

        for item in arr:        
            if sum(item) == target:
                p.append(item)

    return p
0
MarsNebulaSoup