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

                          @JonB, impressive! Need to spend some more time to really follow the logic, but the results match with the brute-force results, so here is the updated version:

                          from itertools import product
                          from math import floor, sqrt
                          
                          def unique_cols(ops, maximum):
                              
                              counts = {
                                  '-': lambda m: m*(m+1)//2,
                                  '+': lambda m: m*(m-1)//2,
                                  '/': lambda m: m**2,
                                  '*': lambda m:
                                      2 * sum([(m//k)-k
                                          for k in range(1, 1 + floor(sqrt(m)))]) +
                                      floor(sqrt(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))
                          
                          1 Reply Last reply Reply Quote 0
                          • JonB
                            JonB @mikael last edited by

                            @mikael shouldn't + and - be the same? In the table of allowables, in the subtraction case you are allowed everything above the diagonal that is along (1,1) to (N,N) (assuming zero is not allowed?). In the plus case, everything above the other diagonal. So both cases are (NN-N)/2==N(N-1)/2

                            I guess it depends on whether you allow 1-1=0 and the like. If so you'd add back N, and get N*(N+1)/2.

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

                              @JonB for multiplication, do you think it is different of mine

                                      for i in range(1,max+1):
                                          col += int(max/i) 
                              
                              mikael 1 Reply Last reply Reply Quote 0
                              • mikael
                                mikael @cvp last edited by mikael

                                @cvp, oh my goodness, my apologies, it looked so simple I did not even understand it is a solution. Which also checks against the brute-force values, hence the simplified version below.

                                @JonB, yes, we include 1-1 as per the ”rules”.

                                def unique_cols(ops, maximum):
                                    
                                    counts = {
                                        '-': lambda m: m*(m+1)//2,
                                        '+': lambda m: m*(m-1)//2,
                                        '/': lambda m: m**2,
                                        '*': lambda m: sum([m//i for i in range(1, m+1)]),
                                    }
                                    return sum([counts[op](maximum) for op in ops])
                                
                                
                                maximum = int(input('Maximum integer: '))
                                ops = input('Operations (one or more of +-*/): ')
                                
                                print('Unique combinations:', unique_cols(ops, maximum))
                                
                                cvp 1 Reply Last reply Reply Quote 0
                                • cvp
                                  cvp @mikael last edited by

                                  @mikael said:

                                  it looked so simple

                                  Haha 😂

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

                                    As terribly interesting as this has been, I am still wondering what it is for...

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

                                      My last version, still without division due to an unanswered question

                                      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):
                                                  col += max - i
                                                  # comment next lines if you don't want detail
                                                  for j in range(1,max-i+1):
                                                      print(i,operators,j,i+j)
                                          elif operators == '-':
                                              for i in range(1,max+1):
                                                  col += i
                                                  # comment next lines if you don't want detail
                                                  for j in range(1,i+1):
                                                      print(i,operators,j,i-j)
                                          elif operators == 'x':
                                              for i in range(1,max+1):
                                                  col += int(max/i)
                                                  # comment next lines if you don't want detail
                                                  for j in range(1,1+int(max/i)):
                                                      print(i,operators,j,i*j)
                                      
                                          return col
                                          
                                      while True:
                                          op = input('operator\n')
                                          max = int(input('max\n'))
                                          print(uniques_col(op,max))
                                          
                                      
                                      1 Reply Last reply Reply Quote 0
                                      • First post
                                        Last post
                                      Powered by NodeBB Forums | Contributors