Combinatorics: Closed formula for assigning an index to each combination of given size - combinatorics

Let's say I have the set {0, 1, 2, 3, 4} and look at combinations of size 3; there are C(5, 3) = 10 of them, e.g. {0,1,2}, {0,1,3}, {0, 1, 4}, {0,2,3} etc.
Is there a closed formula to index each of these combinations, e.g. {0,1,2} --> 0, {0,1,3} --> 1 etc?
In code, if I had:
int index(int i1, int i2, int i3){...}
Then index(0, 1, 2) would return 0, index(0,1,3) would return 1 etc.
My attempt at solving index(i, j, k) was returning
i * 5^2 + j * 5^1 + k * 5^0 - #(junk up to ijk)
where junk are non-combinations, e.g. is stuff like {001, 002, 003, 004} up to {ijk}.

Related

How to find the product of a value * the unique number of times it occurs in a list?

Example if i have a list
[100,50,1,1,1,1]
I want it to output
100 * 1 + 5 * 1 + 1 * 4
Currently Im using a dictionary to do so.
lst = [100, 50, 1, 1, 1, 1, 100]
total = 0
dic = {}
for elem in lst:
if not elem in dic:
dic[elem] = total
#print(dic)
else:
dic[elem] += total + 1
output is alittle off
{100: 1, 50: 0, 1: 3}
100 actually comes twice, and 1 appears 4 times.
So to get how many times you need to multiply each number, you can use the count method.
Knowing that, the problem then becomes looping through unique elements in the original list and then counting/multiplying them from the original list.
To get unique values, we can use a set!
lst = [100, 50, 1, 1, 1, 1, 100]
unique, sum = set(lst), 0
for number in unique:
sum += number * lst.count(number)
print(sum)
If you actually need the dictionary:
lst = [100, 50, 1, 1, 1, 1, 100]
unique, unique_counts = set(lst), {}
for number in unique:
unique_counts[number] = lst.count(number)
print(unique_counts)

Find number of ‘+’ formed by all ones in a binary matrix

The question I have is similar to the problem found here: https://www.geeksforgeeks.org/find-size-of-the-largest-formed-by-all-ones-in-a-binary-matrix/
The difference is the '+' must have all other cells in the matrix to be zeros. For example:
00100
00100
11111
00100
00100
This will be a 5x5 matrix with 2 '+', one inside another.
Another example:
00010000
00010000
00010000
11111111
00010000
00010010
00010111
00010010
This matrix is 8x8, and will have 3 '+', one of it is the small 3x3 matrix in the bottom right, and the other 2 is formed from the 5x5 matrix, one inside another, similar to the first example.
Using the code from the link above, I can only get so far:
M = [[0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 1, 0],
[0, 0, 0, 1, 0, 1, 1, 1], [0, 0, 0, 1, 0, 0, 1, 0]]
R = len(M)
N = len(M)
C = len(M[0])
left = [[0 for k in range(C)] for l in range(R)]
right = [[0 for k in range(C)] for l in range(R)]
top = [[0 for k in range(C)] for l in range(R)]
bottom = [[0 for k in range(C)] for l in range(R)]
for i in range(R):
top[0][i] = M[0][i]
bottom[N - 1][i] = M[N - 1][i]
left[i][0] = M[i][0]
right[i][N - 1] = M[i][N - 1]
for i in range(R):
for j in range(1,R):
if M[i][j] == 1:
left[i][j] = left[i][j - 1] + 1
else:
left[i][j] = 1
if (M[j][i] == 1):
top[j][i] = top[j - 1][i] + 1
else:
top[j][i] = 0
j = N - 1 - j
if (M[j][i] == 1):
bottom[j][i] = bottom[j + 1][i] + 1
else:
bottom[j][i] = 0
if (M[i][j] == 1):
right[i][j] = right[i][j + 1] + 1
else:
right[i][j] = 0
j = N - 1 - j
n = 0
for i in range(N):
for j in range(N):
length = min(top[i][j], bottom[i][j], left[i][j], right[i][j])
if length > n:
n = length
print(n)
Currently, it returns the output of the longest side of the '+'. The desired output would be the number of '+' in the square matrix.
I am having trouble checking for all other cells in the matrix to be zeros, and finding a separate '+' if there is one in the entire matrix.
Any help is greatly appreciated.
I don't want to spoil the fun of solving this problem, so rather than a solution, here are some hints:
Try to write a sub-routine (a function), that given a square matrix as input, decides whether this input matrix is a '+' or not (say the function returns a '1' if it is a '+' and a '0' otherwise).
Modify the function from 1. so that you can give it as input a submatrix of the full matrix (in which you want to count '+'). More specifically, the input could be the coordinate of the upper left entry of the submatrix and its size. The return value should be the same as for 1.
Can you write a loop that examines all the submatrices of your given matrix and counts the ones that are '+' using the function from 2.?
Here are some minor remarks: The algorithm that this leads to runs in polynomial time (in the dimension of the input matrix), so basically it shouldn't take to long.
I haven't thought about it too much, but probably the algorithm can be made more efficient.
Also, you should maybe think about whether or not you count a '1' that is surrounded by '0's as a '+' or not.

Find combinations of one and two that add to a number

I am trying to get every possible combination and permutation of adding one and two to reach a number. For example, you can get to 5 by adding 1 + 1 + 2 or 2 + 2 + 1, etc.
objective:return a list of all lists made of 1's and 2's where the sum of the elements equals the parameter
my code won't work for 0,1, and 2 as pointed out
for example:
3: [1,1,1],[1,2],[2,1]
4: [1,1,1,1],[1,2,1],[2,1,1],[1,1,2],[2,2]
I have figured out a way of doing it, but it only works up till 7, as it won't find the 'middle' combination (not the most 1's or two's, just an average amount).
My function doesn't find any permutations, it just does the combinations.
def findsum(x):
numbers = []
numOfOnes= x - 2
numbers.append([1]*x) # all ones
numbers.append([1] * numOfOnes + [2]) #all ones and a two
if x % 2 == 0:
numOfTwos = int((x - 2)/2)
numbers.append([2]*(int(x/2))) # all twos
if x >= 6:
numbers.append([2] * numOfTwos+ [1,1]) #all twos and 2 ones
else:
numOfTwos = int((x - 1)/2)
numbers.append([2] * numOfTwos+ [1])
return numbers
Usage:
print(findsum(6))
# if number is greater that 7, won't get middle combination. Ex:
# [1,1,1,2,2] = 7 #doesn't have max 1's or 2's, , so won't be found in my algo
# [1,1,2,2,1,1] = 8 #doesn't have max 1's or 2's, so won't be found in my algo.
What you're after are called integer compositions--specifically, compositions that only include 1 and 2.
Because this problem is related to the Fibonacci sequence, it stands to reason that a possible solution would be structurally similar to a Fibonacci algorithm. Here's a recursive version:
def f_rec(n):
assert n >= 0
if n == 0:
return [[]]
elif n == 1:
return [[1]]
else:
return [[1] + composition for composition in f_rec(n - 1)] \
+ [[2] + composition for composition in f_rec(n - 2)]
Explanation: let F(n) = all the compositions of n consisting of only 1's and 2's. Every composition must begin with a 1 or 2.
If a composition of n begins with a 1, then it must be followed by a composition of n - 1. If it begins with a 2, then it must be followed by a composition of n - 2. Hence, all the compositions of n are either 1 followed by all the compositions of n - 1, or 2 followed by all the compositions of n - 2, which is exactly what the recursive case here is "saying".
Here's a basic iterative version:
def f_iter(n):
assert n >= 0
a, b = [[]], [[1]]
for _ in range(n):
a, b = b, [[1] + c for c in b] + [[2] + c for c in a]
return a
For the iterative version, we start from the base cases: a is set to all the compositions of 0 (there is exactly one: the empty composition), and b is set to all the compositions of 1. On each iteration, a and b are "moved forward" by one step. So after one iteration, a := F(1) and b := F(2), then a := F(2) and b := F(3), and so on.
Suppose a := F(k) and b := F(k + 1). The next value of a should be F(k + 1), which is simply the current value of b. To find the next value of b, note that:
if you add a 1 to a composition of k + 1, then you get a composition of k + 2.
if you add a 2 to a composition of k, then you get a composition of k + 2 as well.
in fact, these are the only ways to form a composition of k + 2, since we can only use 1's and 2's.
Thus, the new value of b, which is F(k + 2), is 1 plus all of the old value of b (F(k + 1)) and 2 plus all of the old value of a (F(k)).
Repeat this n times, and you end up with a := F(n) and b := F(n + 1).
Note, however, that because the length of the result is equal to Fibonacci(n+1), both functions above because unusable very quickly.
No needs some complex code to do that.
My function :
def findsum(x) :
base = [1]*x
i = 0
baseMax = ''
while i < x :
try :
baseMax += str(base[i] + base[i+1])
except IndexError :
baseMax += str(base[i])
i += 2
baseList = []
for i, n in enumerate(baseMax) :
if n == '2' :
baseList.append(baseMax[:i].replace('2', '11') + '1'*2 + baseMax[i+1:])
baseList.append(baseMax)
from itertools import permutations
results = set()
for n in baseList :
if n.count('1') and n.count('2') :
for p in sorted(permutations(n, len(n))) :
results.add(''.join(list(p)))
else :
results.add(n)
return sorted(results, key=int)
print(findsum(7))
# ['1222', '2122', '2212', '2221', '11122',
# '11212', '11221', '12112', '12121', '12211',
# '21112', '21121', '21211', '22111', '111112',
# '111121', '111211', '112111', '121111', '211111',
# '1111111']
import math
import itertools
def findCombos(n):
max2s = math.floor(n/2)
min1s = n - max2s
sets = []
#each set includes [numOfTwos,numOfOnes]
for x in range(max2s+1):
sets.append([x,n-(x*2)])
#creates sets of numberOfOnes and numberOfTwos
numsets = []
allsets = []
for x in sets:
numsets.append(x[0] * [2] + x[1] * [1])
#changes set to number form , [2,3] >> [2,2,1,1,1]
for eachset in numsets:
if 1 in eachset and 2 in eachset:
#if can be permutated(has 2 different numbers)
y = set(itertools.permutations(eachset))
#y is all the permutations for that set of numbers
for z in y:
#for each tuple in the list of tuples, append it
allsets.append(z)
else:
#otherwise just append the list as a tuple
allsets.append(tuple(eachset))
return allsets
Usage:
print(findCombos(7))
Output:
[[(1, 1, 1, 1, 1, 1, 1), (1, 1, 1, 1, 1, 2), (1, 2, 1, 1, 1, 1), (1, 1, 1, 2, 1, 1), (1, 1, 2, 1, 1, 1), (2, 1, 1, 1, 1, 1), (1, 1, 1, 1, 2, 1), (1, 2, 1, 1, 2), (2, 1, 1, 1, 2), (2, 1, 2, 1, 1), (2, 1, 1, 2, 1), (1, 1, 2, 1, 2), (1, 1, 1, 2, 2), (1, 2, 2, 1, 1), (1, 2, 1, 2, 1), (1, 1, 2, 2, 1), (2, 2, 1, 1, 1), (2, 2, 1, 2), (2, 1, 2, 2), (2, 2, 2, 1), (1, 2, 2, 2)]

Python: Calculate the last digit of a large Fibonacci Number with less time

# Uses python3
# Compute the Last Digit of a Large Fibonacci Number
def Fib_Last_Digit(n):
if n == 0 : return 0
elif n == 1: return 1
else:
a,b = 0,1
for i in range(1,n):
c = a + b;
a = b;
b = c;
# Calculate the last digit of the final number
lastdigit = int(repr(c)[-1]);
print(lastdigit);
n = int(input(""));
Fib_Last_Digit(n);
This code works very well. However, I want to revise the algorithm to save more time and memory. By the way, the input and output should be kept the same with the previous version.
Only keeping the last digit during calculation saves a lot of time:
def fib_last_digit(n):
if n < 2: return n
else:
a, b = 0, 1
for i in range(1,n):
a, b = b, (a+b) % 10
print(b)
n = int(input())
fib_last_digit(n)
Handling numbers that fit in fewer bytes saves time.
When you're working with huge numbers, you can save a lot of time using the answer described here, slightly modified to only keep track of the last digit:
def fib_last_digit(n):
v1, v2, v3 = 1, 1, 0 # initialise a matrix [[1,1],[1,0]]
for rec in bin(n)[3:]: # perform fast exponentiation of the matrix (quickly raise it to the nth power)
calc = (v2*v2) % 10
v1, v2, v3 = (v1*v1+calc) % 10, ((v1+v3)*v2) % 10, (calc+v3*v3) % 10
if rec == '1': v1, v2, v3 = (v1+v2) % 10, v1, v2
return v2
And finally, based on the concept described in Eugene Yarmash's answer (the last digits repeat every 60 steps) we can make an even faster solution (O(1)):
def fib_last_digit(n):
return (
[1, 1, 2, 3, 5, 8, 3, 1, 4, 5, 9, 4, 3, 7, 0, 7, 7, 4, 1, 5, 6, 1, 7, 8, 5, 3, 8, 1, 9, 0, 9, 9, 8, 7, 5, 2, 7, 9, 6, 5, 1, 6, 7, 3, 0, 3, 3, 6, 9, 5, 4, 9, 3, 2, 5, 7, 2, 9, 1, 0]
[n % 60 - 1]
)
The series of final digits of Fibonacci numbers repeats with a cycle length of 60. Therefore, the Nth Fibonacci number has the same last digit as the (N % 60)th, which should be pretty fast to calculate. As an additional optimization, you can keep only the last digit of each term:
def fib_last_digit(n):
a, b = 0, 1
for i in range(n % 60):
a, b = b, (a + b) % 10
return a
print([fib_last_digit(n) for n in range(1, 11)])
Output:
[1, 1, 2, 3, 5, 8, 3, 1, 4, 5]
def fib(n):
phi = (1 + 5 ** 0.5) / 2
fib_n = round(((phi** n) - (phi**-n) )/(5 ** .5))
return fib_n % 10
Phi is your friend.
def fib_digit(n):
f=[1,1]
for i in range(2,n):
f.append((f[i-1]+f[i-2]) % 10 )
return f[-1]
n = int(input())
print(fib_digit(n))
This is one of the simplest answers,i'm sure, there is a faster algorithm.
Here is what I found:
f1, f2 = 0, 1
for i in range(int(input())-1):
f1, f2 = f2, (f1+f2)%10
print(f2)
It took only --- 0.002832174301147461 seconds --- to complete the code.
import time
n = 100000000000000000000000000000000000000000
def printfib(previous, latest, n):
if(latest > n):
return
print(', ', latest, end='')
printfib(latest, previous + latest, n)
start_time = time.time()
print(0, end='')
printfib(0, 1, n)
print(" ")
print("--- %s seconds ---" % (time.time() - start_time))

Python - assigning digits of a number to variables [duplicate]

This question already has answers here:
How to split an integer into a list of digits?
(10 answers)
Closed last month.
I'm writing a program which calculates the check digit of an ISBN number. I have to read the user's input (nine digits of an ISBN) into an integer variable, and then multiply the last digit by 2, the second last digit by 3 and so on. How can I "split" the integer into its constituent digits to do this? As this is a basic homework exercise I am not supposed to use a list.
Just create a string out of it.
myinteger = 212345
number_string = str(myinteger)
That's enough. Now you can iterate over it:
for ch in number_string:
print ch # will print each digit in order
Or you can slice it:
print number_string[:2] # first two digits
print number_string[-3:] # last three digits
print number_string[3] # forth digit
Or better, don't convert the user's input to an integer (the user types a string)
isbn = raw_input()
for pos, ch in enumerate(reversed(isbn)):
print "%d * %d is %d" % pos + 2, int(ch), int(ch) * (pos + 2)
For more information read a tutorial.
while number:
digit = number % 10
# do whatever with digit
# remove last digit from number (as integer)
number //= 10
On each iteration of the loop, it removes the last digit from number, assigning it to digit.
It's in reverse, starts from the last digit, finishes with the first
list_of_ints = [int(i) for i in str(ISBN)]
Will give you a ordered list of ints. Of course, given duck typing, you might as well work with str(ISBN).
Edit: As mentioned in the comments, this list isn't sorted in the sense of being ascending or descending, but it does have a defined order (sets, dictionaries, etc in python in theory don't, although in practice the order tends to be fairly reliable). If you want to sort it:
list_of_ints.sort()
is your friend. Note that sort() sorts in place (as in, actually changes the order of the existing list) and doesn't return a new list.
On Older versions of Python...
map(int,str(123))
On New Version 3k
list(map(int,str(123)))
(number/10**x)%10
You can use this in a loop, where number is the full number, x is each iteration of the loop (0,1,2,3,...,n) with n being the stop point. x = 0 gives the ones place, x = 1 gives the tens, x = 2 gives the hundreds, and so on. Keep in mind that this will give the value of the digits from right to left, so this might not be the for an ISBN but it will still isolate each digit.
Convert it to string and map over it with the int() function.
map(int, str(1231231231))
Recursion version:
def int_digits(n):
return [n] if n<10 else int_digits(n/10)+[n%10]
Converting to str is definitely slower then dividing by 10.
map is sligthly slower than list comprehension:
convert to string with map 2.13599181175
convert to string with list comprehension 1.92812991142
modulo, division, recursive 0.948769807816
modulo, division 0.699964046478
These times were returned by the following code on my laptop:
foo = """\
def foo(limit):
return sorted(set(map(sum, map(lambda x: map(int, list(str(x))), map(lambda x: x * 9, range(limit))))))
foo(%i)
"""
bar = """\
def bar(limit):
return sorted(set([sum([int(i) for i in str(n)]) for n in [k *9 for k in range(limit)]]))
bar(%i)
"""
rac = """\
def digits(n):
return [n] if n<10 else digits(n / 10)+[n %% 10]
def rabbit(limit):
return sorted(set([sum(digits(n)) for n in [k *9 for k in range(limit)]]))
rabbit(%i)
"""
rab = """\
def sum_digits(number):
result = 0
while number:
digit = number %% 10
result += digit
number /= 10
return result
def rabbit(limit):
return sorted(set([sum_digits(n) for n in [k *9 for k in range(limit)]]))
rabbit(%i)
"""
import timeit
print "convert to string with map", timeit.timeit(foo % 100, number=10000)
print "convert to string with list comprehension", timeit.timeit(bar % 100, number=10000)
print "modulo, division, recursive", timeit.timeit(rac % 100, number=10000)
print "modulo, division", timeit.timeit(rab % 100, number=10000)
After own diligent searches I found several solutions, where each has advantages and disadvantages. Use the most suitable for your task.
All examples tested with the CPython 3.5 on the operation system GNU/Linux Debian 8.
Using a recursion
Code
def get_digits_from_left_to_right(number, lst=None):
"""Return digits of an integer excluding the sign."""
if lst is None:
lst = list()
number = abs(number)
if number < 10:
lst.append(number)
return tuple(lst)
get_digits_from_left_to_right(number // 10, lst)
lst.append(number % 10)
return tuple(lst)
Demo
In [121]: get_digits_from_left_to_right(-64517643246567536423)
Out[121]: (6, 4, 5, 1, 7, 6, 4, 3, 2, 4, 6, 5, 6, 7, 5, 3, 6, 4, 2, 3)
In [122]: get_digits_from_left_to_right(0)
Out[122]: (0,)
In [123]: get_digits_from_left_to_right(123012312312321312312312)
Out[123]: (1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 1, 3, 1, 2, 3, 1, 2, 3, 1, 2)
Using the function divmod
Code
def get_digits_from_right_to_left(number):
"""Return digits of an integer excluding the sign."""
number = abs(number)
if number < 10:
return (number, )
lst = list()
while number:
number, digit = divmod(number, 10)
lst.insert(0, digit)
return tuple(lst)
Demo
In [125]: get_digits_from_right_to_left(-3245214012321021213)
Out[125]: (3, 2, 4, 5, 2, 1, 4, 0, 1, 2, 3, 2, 1, 0, 2, 1, 2, 1, 3)
In [126]: get_digits_from_right_to_left(0)
Out[126]: (0,)
In [127]: get_digits_from_right_to_left(9999999999999999)
Out[127]: (9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9)
Using a construction tuple(map(int, str(abs(number)))
In [109]: tuple(map(int, str(abs(-123123123))))
Out[109]: (1, 2, 3, 1, 2, 3, 1, 2, 3)
In [110]: tuple(map(int, str(abs(1412421321312))))
Out[110]: (1, 4, 1, 2, 4, 2, 1, 3, 2, 1, 3, 1, 2)
In [111]: tuple(map(int, str(abs(0))))
Out[111]: (0,)
Using the function re.findall
In [112]: tuple(map(int, re.findall(r'\d', str(1321321312))))
Out[112]: (1, 3, 2, 1, 3, 2, 1, 3, 1, 2)
In [113]: tuple(map(int, re.findall(r'\d', str(-1321321312))))
Out[113]: (1, 3, 2, 1, 3, 2, 1, 3, 1, 2)
In [114]: tuple(map(int, re.findall(r'\d', str(0))))
Out[114]: (0,)
Using the module decimal
In [117]: decimal.Decimal(0).as_tuple().digits
Out[117]: (0,)
In [118]: decimal.Decimal(3441120391321).as_tuple().digits
Out[118]: (3, 4, 4, 1, 1, 2, 0, 3, 9, 1, 3, 2, 1)
In [119]: decimal.Decimal(-3441120391321).as_tuple().digits
Out[119]: (3, 4, 4, 1, 1, 2, 0, 3, 9, 1, 3, 2, 1)
Use the body of this loop to do whatever you want to with the digits
for digit in map(int, str(my_number)):
I have made this program and here is the bit of code that actually calculates the check digit in my program
#Get the 10 digit number
number=input("Please enter ISBN number: ")
#Explained below
no11 = (((int(number[0])*11) + (int(number[1])*10) + (int(number[2])*9) + (int(number[3])*8)
+ (int(number[4])*7) + (int(number[5])*6) + (int(number[6])*5) + (int(number[7])*4) +
(int(number[8])*3) + (int(number[9])*2))/11)
#Round to 1 dp
no11 = round(no11, 1)
#explained below
no11 = str(no11).split(".")
#get the remainder and check digit
remainder = no11[1]
no11 = (11 - int(remainder))
#Calculate 11 digit ISBN
print("Correct ISBN number is " + number + str(no11))
Its a long line of code, but it splits the number up, multiplies the digits by the appropriate amount, adds them together and divides them by 11, in one line of code. The .split() function just creates a list (being split at the decimal) so you can take the 2nd item in the list and take that from 11 to find the check digit. This could also be made even more efficient by changing these two lines:
remainder = no11[1]
no11 = (11 - int(remainder))
To this:
no11 = (11 - int(no11[1]))
Hope this helps :)
Similar to this answer but more a more "pythonic" way to iterate over the digis would be:
while number:
# "pop" the rightmost digit
number, digit = divmod(number, 10)
How about a one-liner list of digits...
ldigits = lambda n, l=[]: not n and l or l.insert(0,n%10) or ldigits(n/10,l)
Answer: 165
Method: brute-force! Here is a tiny bit of Python (version 2.7) code to count'em all.
from math import sqrt, floor
is_ps = lambda x: floor(sqrt(x)) ** 2 == x
count = 0
for n in range(1002, 10000, 3):
if n % 11 and is_ps(sum(map(int, str(n)))):
count += 1
print "#%i: %s" % (count, n)
Just assuming you want to get the i-th least significant digit from an integer number x, you can try:
(abs(x)%(10**i))/(10**(i-1))
I hope it helps.

Resources