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
    9706
    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 @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
                                          • cvp
                                            cvp @mikael last edited by

                                            @mikael and @ccc I think that I'll stop to believe I can program in Python 😢

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