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.
    • 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
                                          • mikael
                                            mikael @ccc last edited by

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

                                            cvp 1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            Powered by NodeBB Forums | Contributors