Is there a math nCr function in python?
The following program calculates nCr
in an efficient manner (compared to calculating factorials etc.)
import operator as op
from functools import reduce
def ncr(n, r):
r = min(r, n-r)
numer = reduce(op.mul, range(n, n-r, -1), 1)
denom = reduce(op.mul, range(1, r+1), 1)
return numer // denom # or / in Python 2
As of Python 3.8, binomial coefficients are available in the standard library as math.comb
:
>>> from math import comb
>>> comb(10,3)
120
Statistics: combinations in Python
See scipy.special.comb (scipy.misc.comb in older versions of scipy). When exact
is False, it uses the gammaln function to obtain good precision without taking much time. In the exact case it returns an arbitrary-precision integer, which might take a long time to compute.
Is there a built-in function to calculate nCr in C++?
The beta
function from the mathematical library can be used to express binomial coefficients (aka nCr).
double binom(int n, int k) {
return 1/((n+1)*std::beta(n-k+1,k+1));
}
Source.
This function is available either with C++17 or as part of an implementation of the mathematical special functions extensions for C++ (ISO/IEC 29124:2010). In the latter case, your implementation may require you to #define __STDCPP_WANT_MATH_SPEC_FUNCS__ 1
before including the <cmath>
header for the function to be available.
Note that, unlike Python, C++ does not have built-in support for big integer numbers, so using floating point arithmetic is probably a good choice here in the first place.
Python Binomial Coefficient
This question is old but as it comes up high on search results I will point out that scipy
has two functions for computing the binomial coefficients:
scipy.special.binom()
scipy.special.comb()
import scipy.special
# the two give the same results
scipy.special.binom(10, 5)
# 252.0
scipy.special.comb(10, 5)
# 252.0
scipy.special.binom(300, 150)
# 9.375970277281882e+88
scipy.special.comb(300, 150)
# 9.375970277281882e+88
# ...but with `exact == True`
scipy.special.comb(10, 5, exact=True)
# 252
scipy.special.comb(300, 150, exact=True)
# 393759702772827452793193754439064084879232655700081358920472352712975170021839591675861424
Note that scipy.special.comb(exact=True)
uses Python integers, and therefore it can handle arbitrarily large results!
Speed-wise, the three versions give somewhat different results:
num = 300
%timeit [[scipy.special.binom(n, k) for k in range(n + 1)] for n in range(num)]
# 52.9 ms ± 107 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit [[scipy.special.comb(n, k) for k in range(n + 1)] for n in range(num)]
# 183 ms ± 814 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)each)
%timeit [[scipy.special.comb(n, k, exact=True) for k in range(n + 1)] for n in range(num)]
# 180 ms ± 649 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
(and for n = 300
, the binomial coefficients are too large to be represented correctly using float64
numbers, as shown above).
How do you replace factorial, nCr and nPr operations in python?
Here is what you can do:
import re
input_line = "2*x + (9-5)! + 99! + max! + (x-3)! -4"
pattern = "\(.+?\)(?=!)|[0-9]+(?=!)|[a-z]+(?=!)"
result = re.findall(pattern, input_line)
print(result)
output_line = input_line
for match in result:
if match[0] == '(':
output_line = output_line.replace(f"{match}!", f"math.factorial{match}")
else:
output_line = output_line.replace(f"{match}!", f"math.factorial({match})")
print(output_line)
It first creates a regular expression "\(.*?\)(?=!)| [0-9]*(?=!)| [a-z]*(?=!)"
which is then matched against the input line. All matches are stored in result
.
You then replace all matches in the input line with the desired part.
Running this will produce the output:
2*x + math.factorial(9-5) + math.factorial(99) + math.factorial(max) + math.factorial(x-3) -4
You can do it a similar way for other operators.
EDIT: I could not stop myself from trying more.
This gets closer to a good solution, but still has flaws.
import re
input_line = "2*x + (9-5)! + 99! + max! + (x-3)! -4 * ((7 + 2!)!)"
pattern_1 = "[0-9]+(?=!)"
pattern_2 = "[a-z]+(?=!)"
pattern_3 = "\(.+?\)(?=!)"
result_1 = re.findall(pattern_1, input_line)
output_line = input_line
result_3 = re.findall(pattern_3, output_line)
for match in result_3:
output_line = output_line.replace(f"{match}!", f"math.factorial{match}")
for match in result_1:
output_line = output_line.replace(f"{match}!", f"math.factorial({match})")
result_2 = re.findall(pattern_2, input_line)
for match in result_2:
output_line = output_line.replace(f"{match}!", f"math.factorial({match})")
result_3 = re.findall(pattern_3, output_line)
print(output_line)
It creates the output:
2*x + math.factorial(9-5) + math.factorial(99) + math.factorial(max) + math.factorial(x-3) -4 * math.factorial((7 + math.factorial(2)))
Get a number of possible combinations Python
So, you actually need a way to count the Binomial coefficient, right?
import math
def binomial_cooefficient(n: int, k: int) -> int:
n_fac = math.factorial(n)
k_fac = math.factorial(k)
n_minus_k_fac = math.factorial(n - k)
return n_fac/(k_fac*n_minus_k_fac)
This might not be the most optimal implementation, but it works :)
How to avoid redundant steps in calculation of number of permutations?
You can use scipy.special.comb for this. Switching exact
to True
gives the exact answer as an integer at the cost of speed.
>>> from scipy.special import comb
>>> comb(10, 5, exact=False, repetition=False)
252.0
>>> comb(10, 5, exact=True, repetition=False)
252
counting combinations and permutations efficiently
if n is not far from r then using the recursive definition of combination is probably better, since xC0 == 1 you will only have a few iterations:
The relevant recursive definition here is:
nCr = (n-1)C(r-1) * n/r
This can be nicely computed using tail recursion with the following list:
[(n - r, 0), (n - r + 1, 1), (n - r + 2, 2), ..., (n - 1, r - 1), (n, r)]
which is of course easily generated in Python (we omit the first entry since nC0 = 1) by izip(xrange(n - r + 1, n+1), xrange(1, r+1))
Note that this assumes r <= n you need to check for that and swap them if they are not. Also to optimize use if r < n/2 then r = n - r.
Now we simply need to apply the recursion step using tail recursion with reduce. We start with 1 since nC0 is 1 and then multiply the current value with the next entry from the list as below.
from itertools import izip
reduce(lambda x, y: x * y[0] / y[1], izip(xrange(n - r + 1, n+1), xrange(1, r+1)), 1)
Related Topics
Using Backslash in Python (Not to Escape)
Python Function Attributes - Uses and Abuses
Selecting a Row of Pandas Series/Dataframe by Integer Index
Working with Big Data in Python and Numpy, Not Enough Ram, How to Save Partial Results on Disc
Does Python Support MySQL Prepared Statements
Trying to Mock Datetime.Date.Today(), But Not Working
Python Class Instance Variables and Class Variables
How to Sort Unicode Strings Alphabetically in Python
What Does It Mean to "Call" a Function in Python
How to Write a Multidimensional Array to a Text File
Why Are Empty Strings Returned in Split() Results
How to Execute Python Code from Within Visual Studio Code
Python Sharing a Lock Between Processes