Function for recognize quantity of unique combinations

Hello pythonista community. Can someone adwise me formula for recognize quantity of unique combinations when you count to some max digit with sign "" (minus)? Answer can't be under zero.
Example1:
sign = ''
max = 2
22
21
11 we have only three unique combinations.
Example2:
answer can't be upper max:
max = 2
1+1 we have only one unique example.
I already have formula for two signs "+": unic_col=max**2
But i need formula for '+' and ''
And maybe someone know for:
+×
+/
+×/
/×So, i need function like that:
def uniques_col(operators, max):
if operators == '+':
return max**2
elif operators == '+':
return .....
elif operators == '':
return .....
elif operators == '+×':
return .....
......

@lyubomyr83 sorry if I didn't understand correctly, do you want a formula or a script like
def uniques_col(operators, max): n = 0 if operators == '+': for i in range(1,max): for j in range(i,maxi+1): n += 1 print(i,operators,j,'=',i+j) elif operators == '': for i in range(1,max+1): for j in range(1,i+1): n += 1 print(i,operators,j,'=',ij) return n op = input('operator') v = int(input(op)) print(uniques_col(op,v))

@lyubomyr83 Something like this?
# * coding: utf8 * """ Test solution for https://forum.omzsoftware.com/topic/6159/functionforrecognizequantityofuniquecombinations """ import operator OPERATORS = { "+": operator.add, "": operator.sub, "*": operator.mul, "×": operator.mul, } def eval_eq(a, op, b): return OPERATORS[op](a, b) def uniques_col(operators, max): if len(operators) == 0: # we could also just return (max  1) raise ValueError("No operators given!") elif len(operators) > 1: # the code in the question makes it look like we should add # the number of individual operator combinations if multiple # operators are given. n = 0 for op in operators: n += uniques_col(op, max) return n else: combinations = [] for a in range(max, 0, 1): # for a in range(1, max + 1): for b in range(max, 0, 1): # for b in range(1, max + 1): res = eval_eq(a, operators, b) if res > max: # should this be result >= max? continue if res < 0: # result cant be under 0 continue comb = (a, operators, b) print(comb) if comb not in combinations: combinations.append(comb) return len(combinations) if __name__ == "__main__": testdata = [ # format: operators, max, expected ("", 2, 3), ("+", 2, 1), ("+", 2, 4), ("+", 3, 9), ("+*", 3, None), ] for ops, m, exp in testdata: n = uniques_col(ops, m) print("uniques_col({m}, '{o}') > {r}; expected {e}".format(m=m, o=ops, r=n, e=exp))
This produced this output:
(2, '', 2) (2, '', 1) (1, '', 1) uniques_col(2, '') > 3; expected 3 (1, '+', 1) uniques_col(2, '+') > 1; expected 1 (1, '+', 1) (2, '', 2) (2, '', 1) (1, '', 1) uniques_col(2, '+') > 4; expected 4 (2, '+', 1) (1, '+', 2) (1, '+', 1) (3, '', 3) (3, '', 2) (3, '', 1) (2, '', 2) (2, '', 1) (1, '', 1) uniques_col(3, '+') > 9; expected 9 (2, '+', 1) (1, '+', 2) (1, '+', 1) (3, '', 3) (3, '', 2) (3, '', 1) (2, '', 2) (2, '', 1) (1, '', 1) (3, '*', 1) (2, '*', 1) (1, '*', 3) (1, '*', 2) (1, '*', 1) uniques_col(3, '+*') > 14; expected None
Your question is kind of hard to understand, so I am not sure this solution is correct...

@bennr01, nice! Couple of possible, nitpicky refinements:
Do not use
max
as an argument name.Instead of for loops, generate the candidates with:
candidates = itertools.product( range(max_int+1), operations, range(max_int+1) )

@mikael said:
Do not use
max
as an argument name.Generally true, but in this case I wanted to preserve the original function signature used in the question.
Instead of for loops, generate the candidates with:
candidates = itertools.product( range(max_int+1), operations, range(max_int+1) )
Yeah, that is way cleaner.

@bennr01, just read an article on functional programming in Python, so one step further:
import itertools import operator OPERATORS = { "+": operator.add, "": operator.sub, "*": operator.mul, "×": operator.mul, } def uniques_col(operators, max_value): return filter( lambda c: 0 <= OPERATORS[c[1]](c[0], c[2]) <= max_value, itertools.product( range(1, max_value+1), operators, range(1, max_value+1) ) ) print(list(uniques_col('+', 2)))

@lyubomyr83, not an answer to your question, but maybe you can use these bruteforce versions to check the formulas you come up with?

@bennr01, with one more fancy function:
import itertools def uniques_col(operators, max_value): possibles = lambda: range(1, max_value+1) return filter( lambda c: 0 <= eval(''.join(map(str, c))) <= max_value, itertools.product(possibles(), operators, possibles()) ) print(list(uniques_col('+', 2)))

@cvp, thank you all for help!!!
With your function i receive right col for '', but not for '+':def uniques_col(operators, max):
n = 0
if operators == '+':
for i in range(1,max):
for j in range(i,maxi+1):
n += 1
print(i,operators,j,'=',i+j)
elif operators == '':
for i in range(1,max+1):
for j in range(1,i+1):
n += 1
print(i,operators,j,'=',ij)
return nwhile True:
op = input('operator\n')
max = int(input('max\n'))
print(uniques_col(op,max))What i receive:
operator
max4
1  1 = 0
2  1 = 1
2  2 = 0
3  1 = 2
3  2 = 1
3  3 = 0
4  1 = 3
4  2 = 2
4  3 = 1
4  4 = 0
10
operator+
max4
1 + 1 = 2
1 + 2 = 3
1 + 3 = 4
2 + 2 = 4
4Where is 1+3 and 2+1, so for '+' i need receive 6 unique examples.

@lyubomyr83 said:
Where is 1+3 and 2+1,
Ok, I did believe that 1+2 is the same as 2+1, thus I did not generate it.
As I told you, I was not sure to correctly understand 😀Thus it is better to use the other script (of @bennr01 and @mikael ) because it tries all combinations.

last edited by cvp

i think you would want to check 1 to max for both numbers (consider /, max/max=1)

@JonB if you do that, you have to check and skip cases where i+j>max
With « my » formula, no check is needed

Combinatoric iterators:

@ccc I'm always positively surprised by the number of libraries in Python

I went into some kind of halfinsane readability/conciseness optimization/noodling loop on this. Here’s the latest version:
from itertools import product def uniques_col(ops, maximum): number_range = range(1, maximum+1) numbers = list(map(str, number_range)) return filter( lambda c: 0 <= eval(''.join(c)) <= maximum, product(numbers, ops, numbers) ) uniques = uniques_col('+/', 2) print(*[ f"{i+1:4}: {''.join(c)}" for i, c in enumerate(uniques)], sep='\n' )

numbers = [str(i + 1) for i in range(maximum)]
Read “What’s new in Python 3” for a discussion on avoiding map(), reduce(), filter().

@ccc, you take the prize for conciseness, and readability is not bad either.
I was debating the value of separating the range of numbers (problem domain issue) and the conversion to strings (a technical implementation detail).

last edited by

@ccc said:
What’s new in Python 3
For clarity, What’s new in Python 3 does not advice against using
map
andfilter
as such, but against usinglist(map(...))
when a list comprehension can be used instead.Thus, as already said, your amendment makes a lot of sense, but it does not automatically follow that we would change the filter into a comprehension, if we want to leave it up to the user of the function to decide whether to ”collapse” the iterator or not.

@cvp, ha ha. There’s a huge difference and swiftly diminishing returns between ”getting to results” and ”getting to perfect”. While this kind of noodling is fun (for me), your recent track record of real results speaks for itself.