Calculer et générer des factorielles, des permutations et des combinaisons en Python

Affaires

Le module mathématique standard pour les fonctions mathématiques en Python peut être utilisé pour calculer les factorielles. SciPy dispose également de fonctions permettant de calculer le nombre total de permutations\combinaisons.

Le module itertools peut également être utilisé pour générer des permutations et des combinaisons à partir de listes (tableaux), etc. et les énumérer.

Ce qui suit est expliqué ici, avec un exemple de code.

  • factorielle:math.factorial()
  • Calculez le nombre total de permutations
    • math.factorial()
    • scipy.special.perm()
  • Générer et énumérer des permutations à partir d'une liste:itertools.permutations()
  • Calculez le nombre total de combinaisons
    • math.factorial()
    • scipy.special.comb()
    • Comment ne pas utiliser math.factorial()
  • Générer et énumérer des combinaisons à partir de listes:itertools.combinations()
  • Calculer le nombre total de combinaisons en double
  • Générer et énumérer les combinaisons de doublons à partir d'une liste:itertools.combinations_with_replacement()

À titre d'exemple d'utilisation des permutations, on peut également expliquer ce qui suit.

  • Créer des anagrammes à partir de chaînes de caractères

Si vous souhaitez générer une combinaison d'éléments de plusieurs listes au lieu d'une seule, utilisez itertools.product() dans le module itertools.

factorielle: math.factorial()

Le module mathématique fournit une fonction factorielle() qui renvoie la factorielle.

import math

print(math.factorial(5))
# 120

print(math.factorial(0))
# 1

Les valeurs non entières et négatives entraîneront une ValueError.

# print(math.factorial(1.5))
# ValueError: factorial() only accepts integral values

# print(math.factorial(-1))
# ValueError: factorial() not defined for negative values

Calculez le nombre total de permutations

math.factorial()

Les permutations sont le nombre de cas où r sont choisis parmi n différents et placés dans une rangée.

Le nombre total de permutations, p, est obtenu par l'équation suivante en utilisant les factorielles.

p = n! / (n - r)!

Il peut être calculé comme suit à l'aide de la fonction math.factorial(), qui renvoie la factorielle. L'opérateur ⌘, qui effectue la division entière, est utilisé pour retourner un type entier.

def permutations_count(n, r):
    return math.factorial(n) // math.factorial(n - r)

print(permutations_count(4, 2))
# 12

print(permutations_count(4, 4))
# 24

scipy.special.perm()

SciPy fournit une fonction scipy.special.perm() qui renvoie le nombre total de permutations. Une installation séparée de SciPy est requise. Disponible à partir de la version 0.14.0.

from scipy.special import perm

print(perm(4, 2))
# 12.0

print(perm(4, 2, exact=True))
# 12

print(perm(4, 4, exact=True))
# 24

exact=False
Le troisième argument est défini comme ci-dessus par défaut et renvoie un nombre à virgule flottante. Notez que si vous voulez l'obtenir sous forme d'un nombre entier, vous devez le définir comme suit.
exact=True

Notez que seul “import scipy” ne chargera pas le module scipy.special.

Exécutez perm() comme “from scipy.special import perm” comme dans l'exemple ci-dessus, ou exécutez scipy.special.perm() comme “import scipy.special”.

Générer et énumérer des permutations à partir d'une liste: itertools.permutations()

Non seulement les nombres totaux, mais aussi les permutations peuvent être générés et énumérés à partir de listes (tableaux), etc.

Utilisez la fonction permutations() du module itertools.

En passant un itérable (de type liste ou ensemble) comme premier argument et le nombre de pièces à sélectionner comme second argument, on obtient un itérateur pour cette permutation.

import itertools

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

p = itertools.permutations(l, 2)

print(type(p))
# <class 'itertools.permutations'>

Pour les énumérer tous, vous pouvez utiliser une boucle for.

for v in itertools.permutations(l, 2):
    print(v)
# ('a', 'b')
# ('a', 'c')
# ('a', 'd')
# ('b', 'a')
# ('b', 'c')
# ('b', 'd')
# ('c', 'a')
# ('c', 'b')
# ('c', 'd')
# ('d', 'a')
# ('d', 'b')
# ('d', 'c')

Comme il s'agit d'un itérateur fini, il peut également être converti en un type de liste avec list().

Lorsque le nombre d'éléments de la liste est obtenu avec len(), on peut confirmer qu'il correspond au nombre total de permutations calculé à partir de la factorielle.

p_list = list(itertools.permutations(l, 2))

print(p_list)
# [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'a'), ('b', 'c'), ('b', 'd'), ('c', 'a'), ('c', 'b'), ('c', 'd'), ('d', 'a'), ('d', 'b'), ('d', 'c')]

print(len(p_list))
# 12

Si le deuxième argument est omis, la permutation permettant de sélectionner tous les éléments est renvoyée.

for v in itertools.permutations(l):
    print(v)
# ('a', 'b', 'c', 'd')
# ('a', 'b', 'd', 'c')
# ('a', 'c', 'b', 'd')
# ('a', 'c', 'd', 'b')
# ('a', 'd', 'b', 'c')
# ('a', 'd', 'c', 'b')
# ('b', 'a', 'c', 'd')
# ('b', 'a', 'd', 'c')
# ('b', 'c', 'a', 'd')
# ('b', 'c', 'd', 'a')
# ('b', 'd', 'a', 'c')
# ('b', 'd', 'c', 'a')
# ('c', 'a', 'b', 'd')
# ('c', 'a', 'd', 'b')
# ('c', 'b', 'a', 'd')
# ('c', 'b', 'd', 'a')
# ('c', 'd', 'a', 'b')
# ('c', 'd', 'b', 'a')
# ('d', 'a', 'b', 'c')
# ('d', 'a', 'c', 'b')
# ('d', 'b', 'a', 'c')
# ('d', 'b', 'c', 'a')
# ('d', 'c', 'a', 'b')
# ('d', 'c', 'b', 'a')

print(len(list(itertools.permutations(l))))
# 24

Dans itertools.permutations(), les éléments sont traités en fonction de leur position et non de leur valeur. Les valeurs dupliquées ne sont pas prises en compte.

l = ['a', 'a']

for v in itertools.permutations(l, 2):
    print(v)
# ('a', 'a')
# ('a', 'a')

Il en va de même pour les fonctions suivantes, décrites ci-dessous.

  • itertools.combinations()
  • itertools.combinations_with_replacement()

Calculez le nombre total de combinaisons

math.factorial()

Le nombre de combinaisons est le nombre de r pièces à choisir parmi n pièces différentes. L'ordre n'est pas pris en compte comme dans les permutations.

Le nombre total de combinaisons c est obtenu par l'équation suivante.

c = n! / (r! * (n - r)!)

Il peut être calculé comme suit à l'aide de la fonction math.factorial(), qui renvoie la factorielle. L'opérateur ⌘, qui effectue la division entière, est utilisé pour retourner un type entier.

def combinations_count(n, r):
    return math.factorial(n) // (math.factorial(n - r) * math.factorial(r))

print(combinations_count(4, 2))
# 6

scipy.special.comb()

SciPy fournit une fonction scipy.special.comb() qui renvoie le nombre total de permutations. Une installation séparée de SciPy est requise. Disponible à partir de la version 0.14.0. Notez que scipy.special.comb() n'implémente pas la répétition d'arguments décrite ci-dessous.

from scipy.special import comb

print(comb(4, 2))
# 6.0

print(comb(4, 2, exact=True))
# 6

print(comb(4, 0, exact=True))
# 1

exact=False
Comme avec scipy.special.perm(), le troisième argument est défini comme ci-dessus par défaut et renvoie un nombre à virgule flottante. Notez que si vous voulez l'obtenir sous forme d'un nombre entier, vous devez le définir comme suit.
exact=True
Le nombre total de combinaisons dupliquées peut également être obtenu avec le quatrième argument, la répétition. Ceci est décrit ci-dessous.

Encore une fois, notez que seulement “import scipy” ne chargera pas le module scipy.special.

Comme dans l'exemple ci-dessus, exécutez comb() comme “from scipy.special import comb” ou exécutez scipy.special.comb() comme “import scipy.special”. Il en va de même pour “scipy.misc”.

Comment ne pas utiliser math.factorial()

Une autre méthode qui utilise uniquement la bibliothèque standard et qui est plus rapide que la méthode utilisant math.factorial() est la méthode suivante.

from operator import mul
from functools import reduce

def combinations_count(n, r):
    r = min(r, n - r)
    numer = reduce(mul, range(n, n - r, -1), 1)
    denom = reduce(mul, range(1, r + 1), 1)
    return numer // denom

print(combinations_count(4, 2))
# 6

print(combinations_count(4, 0))
# 1

Générer et énumérer des combinaisons à partir de listes: itertools.combinations()

Il est possible de générer et d'énumérer toutes les combinaisons à partir de listes (tableaux), etc. ainsi que les nombres totaux.

Utilisez la fonction combinations() du module itertools.

En passant un itérable (de type liste ou ensemble) comme premier argument et le nombre de pièces à sélectionner comme second argument, on obtient l'itérateur pour cette combinaison.

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

c = itertools.combinations(l, 2)

print(type(c))
# <class 'itertools.combinations'>

for v in itertools.combinations(l, 2):
    print(v)
# ('a', 'b')
# ('a', 'c')
# ('a', 'd')
# ('b', 'c')
# ('b', 'd')
# ('c', 'd')

c_list = list(itertools.combinations(l, 2))

print(c_list)
# [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]

print(len(c_list))
# 6

Calculer le nombre total de combinaisons en double

Le nombre de combinaisons doubles est le nombre de cas dans lesquels r sont choisis parmi n combinaisons différentes, en tenant compte des doubles.

Le nombre total de combinaisons dupliquées est égal au nombre de combinaisons à choisir (r) parmi (n + r – 1) combinaisons différentes.

Par conséquent, nous pouvons utiliser la fonction définie ci-dessus pour calculer le nombre total de combinaisons.

def combinations_with_replacement_count(n, r):
    return combinations_count(n + r - 1, r)

print(combinations_with_replacement_count(4, 2))
# 10

Dans “scipy.special.comb()” décrit ci-dessus, le nombre total de combinaisons dupliquées peut être obtenu en définissant le quatrième argument “repetition=True”.
Notez que l'argument “répétition” n'est pas implémenté dans “scipy.misc.comb()” dans les versions antérieures à “SciPy0.14.0”.

from scipy.special import comb
print(comb(4, 2, exact=True, repetition=True))
# 10

Générer et énumérer les combinaisons de doublons à partir d'une liste: itertools.combinations_with_replacement()

Il est possible de générer et d'énumérer toutes les combinaisons dupliquées à partir de listes (tableaux), etc. ainsi que les nombres totaux.

Utilisez la fonction combinations_with_replacement() du module itertools.

En passant un itérable (de type liste ou ensemble) comme premier argument et le nombre de pièces à sélectionner comme second argument, on obtient un itérateur pour cette combinaison de recouvrement.

h = itertools.combinations_with_replacement(l, 2)

print(type(h))
# <class 'itertools.combinations_with_replacement'>

for v in itertools.combinations_with_replacement(l, 2):
    print(v)
# ('a', 'a')
# ('a', 'b')
# ('a', 'c')
# ('a', 'd')
# ('b', 'b')
# ('b', 'c')
# ('b', 'd')
# ('c', 'c')
# ('c', 'd')
# ('d', 'd')

h_list = list(itertools.combinations_with_replacement(l, 2))

print(h_list)
# [('a', 'a'), ('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'b'), ('b', 'c'), ('b', 'd'), ('c', 'c'), ('c', 'd'), ('d', 'd')]

print(len(h_list))
# 10

Créer des anagrammes à partir de chaînes de caractères

Itertools.permutations() permet de créer facilement des permutations de chaînes de caractères (anagrammes).

s = 'arc'

for v in itertools.permutations(s):
    print(v)
# ('a', 'r', 'c')
# ('a', 'c', 'r')
# ('r', 'a', 'c')
# ('r', 'c', 'a')
# ('c', 'a', 'r')
# ('c', 'r', 'a')

Pour combiner un tuple d'un caractère à la fois dans une chaîne de caractères et en faire une liste, procédez comme suit

anagram_list = [''.join(v) for v in itertools.permutations(s)]

print(anagram_list)
# ['arc', 'acr', 'rac', 'rca', 'car', 'cra']

La méthode join(), qui concatène les éléments d'une liste ou d'un tuple dans une chaîne de caractères, et la notation de compréhension de liste sont utilisées.