omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    Function for recognize quantity of unique combinations

    Pythonista
    6
    37
    10361
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • lyubomyr83
      lyubomyr83 last edited by lyubomyr83

      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
      2-2
      2-1
      1-1

      • 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 .....
      ......

      mikael 2 Replies Last reply Reply Quote 1
      • mikael
        mikael @lyubomyr83 last edited by

        @lyubomyr83, I am confused by the problem definition. What is max?

        • Largest digit to be used in the calculations, or
        • largest allowed result of a calculation, or
        • both of the above?

        Also, what do you need this for?

        lyubomyr83 1 Reply Last reply Reply Quote 1
        • lyubomyr83
          lyubomyr83 @mikael last edited by lyubomyr83

          @mikael
          Max - variable count to, for example 100.
          So i need count quantity uniques examples for some mathematic operator, in my case '+' or '-'
          I can't have example 98+10 or 25-50
          Max example result must be under 100 or equal
          Minimum example result must be under 0

          cvp bennr01 2 Replies Last reply Reply Quote 1
          • cvp
            cvp @lyubomyr83 last edited by

            @lyubomyr83 said:

            Minimum example result must be under 0

            upper 0

            cvp 1 Reply Last reply Reply Quote 1
            • cvp
              cvp @cvp last edited by cvp

              @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,max-i+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,'=',i-j)
              	return n
              
              op = input('operator')
              v = int(input(op))
              print(uniques_col(op,v))
              
              lyubomyr83 1 Reply Last reply Reply Quote 1
              • bennr01
                bennr01 @lyubomyr83 last edited by bennr01

                @lyubomyr83 Something like this?

                # -*- coding: utf-8 -*-
                """
                Test solution for https://forum.omz-software.com/topic/6159/function-for-recognize-quantity-of-unique-combinations
                """
                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...

                mikael 1 Reply Last reply Reply Quote 1
                • mikael
                  mikael @bennr01 last edited by mikael

                  @bennr01, nice! Couple of possible, nit-picky 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)
                  )
                  
                  bennr01 1 Reply Last reply Reply Quote 1
                  • bennr01
                    bennr01 @mikael last edited by

                    @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.

                    mikael 2 Replies Last reply Reply Quote 0
                    • mikael
                      mikael @bennr01 last edited by

                      @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)))
                      
                      1 Reply Last reply Reply Quote 1
                      • mikael
                        mikael @lyubomyr83 last edited by

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

                        1 Reply Last reply Reply Quote 0
                        • mikael
                          mikael @bennr01 last edited by mikael

                          @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)))
                          
                          1 Reply Last reply Reply Quote 1
                          • lyubomyr83
                            lyubomyr83 @cvp last edited by lyubomyr83

                            @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,max-i+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,'=',i-j)
                            return n

                            while 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
                            4

                            Where is 1+3 and 2+1, so for '+' i need receive 6 unique examples.

                            cvp 2 Replies Last reply Reply Quote 0
                            • cvp
                              cvp @lyubomyr83 last edited by cvp

                              @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.

                              1 Reply Last reply Reply Quote 0
                              • cvp
                                cvp @lyubomyr83 last edited by cvp

                                @lyubomyr83

                                Or Change into

                                    if operators == '+':
                                        for i in range(1,max):
                                            for j in range(1,max-i+1): 
                                
                                lyubomyr83 1 Reply Last reply Reply Quote 0
                                • JonB
                                  JonB last edited by

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

                                  cvp 1 Reply Last reply Reply Quote 0
                                  • cvp
                                    cvp @JonB last edited by cvp

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

                                    1 Reply Last reply Reply Quote 0
                                    • ccc
                                      ccc last edited by

                                      Combinatoric iterators:

                                      • https://docs.python.org/3/library/itertools.html#itertools.combinations
                                      • https://docs.python.org/3/library/itertools.html#itertools.combinations_with_replacement
                                      • https://docs.python.org/3/library/itertools.html#itertools.permutations
                                      cvp 1 Reply Last reply Reply Quote 0
                                      • cvp
                                        cvp @ccc last edited by

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

                                        1 Reply Last reply Reply Quote 0
                                        • mikael
                                          mikael last edited by

                                          I went into some kind of half-insane 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'
                                          )
                                          
                                          1 Reply Last reply Reply Quote 1
                                          • ccc
                                            ccc last edited by ccc

                                            numbers = [str(i + 1) for i in range(maximum)]

                                            Read “What’s new in Python 3” for a discussion on avoiding map(), reduce(), filter().

                                            mikael 2 Replies Last reply Reply Quote 1
                                            • First post
                                              Last post
                                            Powered by NodeBB Forums | Contributors