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 @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
                            • mikael
                              mikael @ccc 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 and filter as such, but against using list(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.

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

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

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

                                  @mikael you're too kind 😳

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

                                    @cvp thank's a lot. It working for '+', '-' and '+-':

                                    def uniques_col(operators, max):
                                        col = 0
                                        if operators == '+':
                                            for i in range(1,max):
                                                for j in range(1,max-i+1):
                                                    col += 1
                                        elif operators == '-':
                                            for i in range(1,max+1):
                                                for j in range(1,i+1):
                                                    col += 1
                                        elif operators == '+-':
                                                col = max**2
                                        
                                        return col
                                        
                                    
                                    while True:
                                        op = input('operator\n')
                                        max = int(input('max\n'))
                                        print(uniques_col(op,max))
                                    
                                    And maybe you know uniques col for:
                                    +-×
                                    +-/
                                    +-×/
                                    /×
                                    

                                    ??? Thank's in advance!!!

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

                                      @lyubomyr83, this code:

                                      from itertools import product
                                      
                                      def uniques_col(ops, maximum):
                                          numbers = [str(i+1) for i in range(maximum)]
                                          return filter(
                                              lambda c: 0 <= eval(''.join(c)) <= maximum,
                                              product(numbers, ops, numbers)
                                          )
                                      
                                      ops_list = ['+-*', '+-/', '+-/*', '/*']
                                      to_limit = 20
                                      
                                      for ops in ops_list:
                                          print('-'*20)
                                          print('ops', ops)
                                          for maximum in range(1, to_limit+1):
                                              print(maximum, len(list(
                                                  uniques_col(ops, maximum))))
                                      

                                      ... gives series up to 20 for each set of operations. For +-/, I can deduct that the formula for possibilities is 2*max*max. For the others, not as easy, need to dig out a maths book or two.

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

                                        @lyubomyr83 please try this and tell us if non integer result is allowed for division

                                        def uniques_col(operators, max):
                                            col = 0
                                            if len(operators) > 1:
                                                for op in operators:
                                                    col += uniques_col(op, max)
                                                return col
                                            if operators == '+':
                                                for i in range(1,max):
                                                    for j in range(1,max-i+1):
                                                        print(i,operators,j,i+j)
                                                        col += 1
                                            elif operators == '-':
                                                for i in range(1,max+1):
                                                    for j in range(1,i+1):
                                                        print(i,operators,j,i-j)
                                                        col += 1
                                            elif operators == 'x':
                                                for i in range(1,max+1):
                                                    for j in range(1,1+int(max/i)):
                                                        print(i,operators,j,i*j)
                                                        col += 1
                                        
                                            return col
                                            
                                        while True:
                                            op = input('operator\n')
                                            max = int(input('max\n')) 
                                        
                                        1 Reply Last reply Reply Quote 0
                                        • mikael
                                          mikael @lyubomyr83 last edited by mikael

                                          @lyubomyr83, here’s a version that tries to be smart where possible. Unfortunately, finding the number of unique combinations for multiplication * seems to be directly related to finding the factors of an integer, for which there is no straight-forward formula (hence, public key cryptography works), so we still have to brute-force it.

                                          from functools import reduce
                                          from itertools import product
                                          
                                          def unique_cols(ops, maximum):
                                              
                                              counts = {
                                                  '-': lambda m: m*(m+1)//2,
                                                  '+': lambda m: m*(m-1)//2,
                                                  '/': lambda m: m**2,
                                                  '*': lambda m: len(list(filter(
                                                      lambda c: 0 <= eval(''.join(c)) <= m,
                                                      product([str(i+1) for i in range(m)], '*', [str(i+1) for i in range(m)])
                                                  )))
                                              }
                                              return sum([counts[op](maximum) for op in ops])
                                          
                                          maximum = int(input('Maximum integer: '))
                                          ops = input('Operations (one of more of +-*/): ')
                                          
                                          print('Unique combinations:', unique_cols(ops, maximum))
                                          
                                          JonB 1 Reply Last reply Reply Quote 0
                                          • JonB
                                            JonB last edited by JonB

                                            For multiplication, it seems the number would be something like this:. Consider building the 2d multiplication table, 1..N in cold and rows. Then count how many you have in each row that are <=N. To avoid double counting, handle the diagonal separately.

                                            For each row of the multiplication table, excluding the diagonal, you get

                                            1*x (x!=1)    ==>  N-1 different possiblities
                                            2*x (x!=2)    ==>  (N//2)-1
                                            ...
                                            K*x  (x!=K)    ==>  (N//k)-1
                                            

                                            Then for the diagonal, it is the number of x**2<N
                                            Or, x<=sqrt(N)

                                            So the total is:

                                            sum([(N//k) for k in range(1,N+1)])-N+floor(sqrt (N) )
                                            
                                            Or
                                            
                                            sum([(N//k) for k in range(2,N+1)])+floor(sqrt (N) )
                                            

                                            Not quite brute force, but order N instead of N**2. You could also make use of the symmetry to only count through sqrt(N), which makes it order sqrt (N)..

                                            2*sum([(N//k)-k for k in range(1,1+floor(sqrt(N))])+floor(sqrt (N) )
                                            mikael 1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            Powered by NodeBB Forums | Contributors