Υπολογισμός και δημιουργία παραγοντικών, μεταθέσεων και συνδυασμών στην Python

Επιχείρηση

Η τυπική ενότητα math για μαθηματικές συναρτήσεις στην Python μπορεί να χρησιμοποιηθεί για τον υπολογισμό των παραγοντικών. Η SciPy διαθέτει επίσης συναρτήσεις για τον υπολογισμό του συνολικού αριθμού των μεταθέσεων\συνδυασμών.

Η ενότητα itertools μπορεί επίσης να χρησιμοποιηθεί για τη δημιουργία μεταθέσεων και συνδυασμών από λίστες (πίνακες) κ.λπ. και την απαρίθμησή τους.

Τα παρακάτω εξηγούνται εδώ, μαζί με δείγμα κώδικα.

  • παραγοντικό:math.factorial()
  • Υπολογίστε το συνολικό αριθμό των μεταθέσεων
    • math.factorial()
    • scipy.special.perm()
  • Δημιουργία και απαρίθμηση μεταθέσεων από μια λίστα:itertools.permutations()
  • Υπολογίστε το συνολικό αριθμό των συνδυασμών
    • math.factorial()
    • scipy.special.comb()
    • Πώς να μην χρησιμοποιήσετε την math.factorial()
  • Δημιουργία και απαρίθμηση συνδυασμών από λίστες:itertools.combinations()
  • Υπολογίστε το συνολικό αριθμό των διπλών συνδυασμών
  • Δημιουργία και απαρίθμηση διπλών συνδυασμών από μια λίστα:itertools.combinations_with_replacement()

Ως παράδειγμα χρήσης των μεταθέσεων, εξηγούνται επίσης τα ακόλουθα.

  • Δημιουργία αναγραμμάτων από συμβολοσειρές

Αν θέλετε να δημιουργήσετε έναν συνδυασμό στοιχείων από πολλαπλές λίστες αντί για μία μόνο λίστα, χρησιμοποιήστε την itertools.product() στην ενότητα itertools.

παραγοντικό: math.factorial()

Η ενότητα math παρέχει μια συνάρτηση factorial() που επιστρέφει το παραγοντικό.

import math

print(math.factorial(5))
# 120

print(math.factorial(0))
# 1

Μη ακέραιες, αρνητικές τιμές θα οδηγήσουν σε ValueError.

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

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

Υπολογίστε το συνολικό αριθμό των μεταθέσεων

math.factorial()

Οι αντιμεταθέσεις είναι ο αριθμός των περιπτώσεων όπου r επιλέγονται από n διαφορετικά και τοποθετούνται σε μια σειρά.

Ο συνολικός αριθμός των μεταθέσεων, p, προκύπτει από την ακόλουθη εξίσωση με τη χρήση παραγοντικών.

p = n! / (n - r)!

Μπορεί να υπολογιστεί ως εξής χρησιμοποιώντας τη συνάρτηση math.factorial(), η οποία επιστρέφει το παραγοντικό. Ο τελεστής ⌘, ο οποίος εκτελεί ακέραια διαίρεση, χρησιμοποιείται για να επιστρέψει έναν ακέραιο τύπο.

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 παρέχει μια συνάρτηση scipy.special.perm() που επιστρέφει το συνολικό αριθμό των μεταθέσεων. Απαιτείται ξεχωριστή εγκατάσταση της SciPy. Διαθέσιμη από την έκδοση 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
Το τρίτο όρισμα ορίζεται όπως παραπάνω από προεπιλογή και επιστρέφει έναν αριθμό κινητής υποδιαστολής. Σημειώστε ότι αν θέλετε να το λάβετε ως ακέραιο αριθμό, πρέπει να το ορίσετε ως εξής.
exact=True

Σημειώστε ότι μόνο το «import scipy» δεν θα φορτώσει την ενότητα scipy.special.

Εκτελέστε την perm() ως «from scipy.special import perm» όπως στο παραπάνω παράδειγμα ή εκτελέστε την scipy.special.perm() ως «import scipy.special».

Δημιουργία και απαρίθμηση μεταθέσεων από μια λίστα: itertools.permutations()

Όχι μόνο οι συνολικοί αριθμοί, αλλά και οι μεταθέσεις μπορούν να δημιουργηθούν και να απαριθμηθούν από λίστες (πίνακες) κ.λπ.

Χρησιμοποιήστε τη συνάρτηση permutations() της ενότητας itertools.

Περνώντας έναν επαναλήπτη (τύπου λίστας ή συνόλου) ως πρώτο όρισμα και τον αριθμό των τεμαχίων που πρέπει να επιλεγούν ως δεύτερο όρισμα, επιστρέφεται ένας επαναλήπτης για την εν λόγω αντιμετάθεση.

import itertools

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

p = itertools.permutations(l, 2)

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

Για να τα απαριθμήσετε όλα, μπορείτε να χρησιμοποιήσετε έναν βρόχο 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')

Δεδομένου ότι είναι ένας πεπερασμένος επαναλήπτης, μπορεί επίσης να μετατραπεί σε τύπο λίστας με την list().

Όταν ο αριθμός των στοιχείων της λίστας λαμβάνεται με την len(), μπορεί να επιβεβαιωθεί ότι ταιριάζει με τον συνολικό αριθμό των μεταθέσεων που υπολογίζεται από το παραγοντικό.

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

Εάν το δεύτερο όρισμα παραλείπεται, επιστρέφεται η μετάθεση για την επιλογή όλων των στοιχείων.

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

Στην itertools.permutations(), τα στοιχεία αντιμετωπίζονται με βάση τη θέση και όχι την τιμή. Οι διπλές τιμές δεν λαμβάνονται υπόψη.

l = ['a', 'a']

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

Το ίδιο ισχύει και για τις ακόλουθες λειτουργίες, οι οποίες περιγράφονται παρακάτω.

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

Υπολογίστε το συνολικό αριθμό των συνδυασμών

math.factorial()

Ο αριθμός των συνδυασμών είναι ο αριθμός των r κομματιών που μπορείτε να επιλέξετε από n διαφορετικά κομμάτια. Η σειρά δεν λαμβάνεται υπόψη όπως στις μεταθέσεις.

Ο συνολικός αριθμός συνδυασμών c προκύπτει από την ακόλουθη εξίσωση.

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

Μπορεί να υπολογιστεί ως εξής χρησιμοποιώντας τη συνάρτηση math.factorial(), η οποία επιστρέφει το παραγοντικό. Ο τελεστής ⌘, ο οποίος εκτελεί ακέραια διαίρεση, χρησιμοποιείται για να επιστρέψει έναν ακέραιο τύπο.

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 παρέχει μια συνάρτηση scipy.special.comb() που επιστρέφει το συνολικό αριθμό των μεταθέσεων. Απαιτείται ξεχωριστή εγκατάσταση της SciPy. Διατίθεται από την έκδοση 0.14.0. Σημειώστε ότι η scipy.misc.comb() δεν υλοποιεί την επανάληψη των επιχειρημάτων που περιγράφεται παρακάτω.

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
Όπως και με την scipy.special.perm(), το τρίτο όρισμα ορίζεται όπως παραπάνω από προεπιλογή και επιστρέφει έναν αριθμό κινητής υποδιαστολής. Σημειώστε ότι αν θέλετε να το λάβετε ως ακέραιο, πρέπει να το ορίσετε ως εξής.
exact=True
Ο συνολικός αριθμός των διπλών συνδυασμών μπορεί επίσης να ληφθεί με το τέταρτο όρισμα, την επανάληψη. Αυτό περιγράφεται παρακάτω.

Και πάλι, σημειώστε ότι μόνο το «import scipy» δεν θα φορτώσει την ενότητα scipy.special.

Όπως στο παραπάνω παράδειγμα, εκτελέστε την comb() ως «from scipy.special import comb» ή εκτελέστε την scipy.special.comb() ως «import scipy.special». Το ίδιο ισχύει και για το «scipy.misc».

Πώς να μην χρησιμοποιήσετε την math.factorial()

Μια άλλη μέθοδος που χρησιμοποιεί μόνο την τυπική βιβλιοθήκη και είναι ταχύτερη από τη μέθοδο που χρησιμοποιεί την math.factorial() είναι η ακόλουθη μέθοδος.

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

Δημιουργία και απαρίθμηση συνδυασμών από λίστες: itertools.combinations()

Είναι δυνατόν να δημιουργηθούν και να απαριθμηθούν όλοι οι συνδυασμοί από λίστες (πίνακες), κ.λπ. καθώς και οι συνολικοί αριθμοί.

Χρησιμοποιήστε τη συνάρτηση combinations() της ενότητας itertools.

Παραδίδοντας έναν επαναλήπτη (τύπου λίστας ή συνόλου) ως πρώτο όρισμα και τον αριθμό των τεμαχίων που πρέπει να επιλεγούν ως δεύτερο όρισμα, επιστρέφεται ο επαναλήπτης για αυτόν τον συνδυασμό.

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

Υπολογίστε το συνολικό αριθμό των διπλών συνδυασμών

Ο αριθμός των διπλών συνδυασμών είναι ο αριθμός των περιπτώσεων στις οποίες το r επιλέγεται από n διαφορετικούς συνδυασμούς, επιτρέποντας τα διπλά.

Ο συνολικός αριθμός των διπλών συνδυασμών είναι ίσος με τον αριθμό των συνδυασμών για την επιλογή (r) από (n + r – 1) διαφορετικούς συνδυασμούς.

Επομένως, μπορούμε να χρησιμοποιήσουμε τη συνάρτηση που ορίστηκε παραπάνω για να υπολογίσουμε τον συνολικό αριθμό των συνδυασμών.

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

print(combinations_with_replacement_count(4, 2))
# 10

Στο «scipy.special.comb()» που περιγράφεται παραπάνω, ο συνολικός αριθμός των διπλών συνδυασμών μπορεί να ληφθεί θέτοντας το τέταρτο όρισμα «repetition=True.
Σημειώστε ότι το επιχείρημα «repetition» δεν υλοποιείται στο «scipy.misc.comb()» σε εκδόσεις πριν από τη «SciPy0.14.0».

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

Δημιουργία και απαρίθμηση διπλών συνδυασμών από μια λίστα: itertools.combinations_with_replacement()

Είναι δυνατό να δημιουργηθούν και να απαριθμηθούν όλοι οι διπλοί συνδυασμοί από λίστες (πίνακες) κ.λπ. καθώς και οι συνολικοί αριθμοί.

Χρησιμοποιήστε τη συνάρτηση combinations_with_replacement() στην ενότητα itertools.

Περνώντας έναν επαναλήπτη (τύπου λίστας ή συνόλου) ως πρώτο όρισμα και τον αριθμό των τεμαχίων που πρέπει να επιλεγούν ως δεύτερο όρισμα, επιστρέφεται ένας επαναλήπτης για αυτόν τον επικαλυπτόμενο συνδυασμό.

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

Δημιουργία αναγραμμάτων από συμβολοσειρές

Η Itertools.permutations() διευκολύνει τη δημιουργία μεταθέσεων συμβολοσειρών (αναγραμματισμών).

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

Για να συνδυάσετε μια πλειάδα ενός χαρακτήρα κάθε φορά σε μια συμβολοσειρά και να τη μετατρέψετε σε λίστα, κάντε τα εξής

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

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

Χρησιμοποιείται η μέθοδος join(), η οποία συνενώνει τα στοιχεία μιας λίστας ή μιας πλειάδας σε μια συμβολοσειρά, και ο συμβολισμός κατανόησης λίστας.