-4

I want to creata a python function that will output a tuple which will be in the form of integers. The function should calculate how many rows and columns can be created from this number. For e.g. I input 35, the two possible outputs are (7,5) or (5,7) where the first number is the row and 2nd the column. in case the number is say 20 then it should ouput ( 4,5) or (5,5)

I tried using modulus to determine this but is is not coming up accurately.

4 Answers4

0

Utilising the answer from What is the most efficient way of finding all the factors of a number in Python? suggesting in the comments, you could do the following:

from functools import reduce

def factors(n):
    return set(
        reduce(
            list.__add__,
            ([i, n//i] for i in range(1, int(n**0.5) + 1) if n % i == 0)
        )
     )

def rows_cols(n):
    facs = sorted(factors(n))  # get sorted list of all factors

    # get all pairs of factors (both ways round)
    l = [
            [
                (facs[i], facs[len(facs) - (i + 1)]),
                (facs[len(facs) - (i + 1)], facs[i])
            ]
            for i in range(int(len(facs) / 2))
        ]

    return l

Then you have, e.g.,

print(rows_cols(45))
[[(1, 45), (45, 1)], [(3, 15), (15, 3)], [(5, 9), (9, 5)]]
Matt Pitkin
  • 3,989
  • 1
  • 18
  • 32
0

This is trivial and really isn't aided by importing anything. If the input values are very large then more complex code involving checks for primeness may improve performance

def func(n: int) -> tuple[int, ...]:
    for m in range(int(n**0.5), 1, -1):
        if n % m == 0:
            return m, n//m
    return 1, n

for n in 35, 36, 37, 38, 39, 40:
    print(func(n))

Output:

(5, 7)
(6, 6)
(1, 37)
(2, 19)
(3, 13)
(5, 8)
DarkKnight
  • 19,739
  • 3
  • 6
  • 22
  • Bogosort (https://en.wikipedia.org/wiki/Bogosort) also has an acceptable running time for small collections. – aiootp Aug 14 '23 at 13:57
0

I modified Matt's answer to account for 25 (5 rows, 5 cols).

from functools import reduce
from math import ceil, sqrt

def factors(n):
    return sorted(
        set(
            reduce(
                list.__add__,
                (
                    [i, n//i]
                    for i in range(1, int(sqrt(n)) + 1)  # sqrt is faster than **0.5
                    if n % i == 0
                )
            )
        )
    )

def rows_cols(n):
    facs = factors(n)
    return sorted(
        set(
            reduce(
                list.__add__,
                (
                    [
                        (facs[i], facs[len(facs) - 1 - i]),
                        (facs[len(facs) - 1 - i], facs[i])
                    ]
                    for i in range(ceil(len(facs) / 2))  # Round up
                )
            )
        )
    )
    
if __name__ == '__main__':
    print(f'12 = {rows_cols(12)}') # [(1, 12), (2, 6), (3, 4), (4, 3), (6, 2), (12, 1)]
    print(f'25 = {rows_cols(25)}') # [(1, 25), (5, 5), (25, 1)]
    print(f'45 = {rows_cols(45)}') # [(1, 45), (3, 15), (5, 9), (9, 5), (15, 3), (45, 1)]
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
-1

It sounds like you are trying to factor a number. The fastest algorithm to do that is implemented by the cypari package. It has been suggested for factoring very large numbers, and for abstracting away the decision of the best algorithm to choose. If your numbers stay small, and you only need to calculate rows and columns infrequently, then trial division is acceptable. But, if you expect your numbers to vary in size significantly, and/or you are doing this calculation often, then it's best to use an efficient algorithm.

To find the factors using cypari:

from cypari import pari

number = 35

factors = [int(factor) for factor in pari.factor(number).list()[0]]

print(factors)
[5, 7]

Then to get all the combinations of rows and columns:

combinations = [(row, number // row) for row in (factors + [1, number])]

print(combinations)
[(5, 7), (7, 5), (1, 35), (35, 1)]
aiootp
  • 154
  • 4
  • 1
    It would be much more efficient to calculate `col = number // row` rather than testing every possible combination of `row` and `col` and rejecting those that don't multiply to the right result. Doing that is O(N^2) in the number of factors. – slothrop Aug 14 '23 at 15:08
  • On average, that is not true. The number of factors N is log (log (N)) on average. (See: https://en.wikipedia.org/wiki/Erd%C5%91s%E2%80%93Kac_theorem). So, the complexity would be O( log(log(N)) ** 2 ), which is much less than the O(N) complexity of your suggestion. – aiootp Aug 14 '23 at 15:13
  • That's why I said O(N^2) **in the number of factors**, not in `number` itself. – slothrop Aug 14 '23 at 15:14
  • 1
    `combinations = [(row, number // row) for row in factors + [1, number]]` is both quicker and simpler than iterating over the Cartesian product. – slothrop Aug 14 '23 at 15:16
  • I see what you're saying. That's a great improvement, thank you! – aiootp Aug 14 '23 at 15:18