"""
Consider all integer combinations of ab for 2 â‰¤ a â‰¤ 5 and 2 â‰¤ b â‰¤ 5:

    2^2=4, 2^3=8, 2^4=16, 2^5=32
    3^2=9, 3^3=27, 3^4=81, 3^5=243
    4^2=16, 4^3=64, 4^4=256, 4^5=1024
    5^2=25, 5^4=125, 5^4=625, 5^5=3125

If they are then placed in numerical order, with any repeats removed, we get
    the following sequence of 15 distinct terms:

4, 8, 9, 16, 25, 27, 32, 64, 81, 125, 243, 256, 625, 1024, 3125

How many distinct terms are in the sequence generated by ab for 2 â‰¤ a â‰¤ 100
    and 2 â‰¤ b â‰¤ 100?
"""

from timeit import timeit


def problema(a, b):
    c = set()
    l = r = range(a, b + 1)
    for i in l:
        for j in r:
            c = c | {i ** j}  # Con esto concatenamos 'set'

    return len(c)


def problema_pythonico(a, b):
    """ Mucho mÃ¡s rÃ¡pido en este caso """
    return len({i ** j for i in range(a, b+1) for j in range(a, b+1)})

if __name__ == "__main__":
    def wrapper(problema, *args, **kwargs):
        def wrapped():
            return problema(*args, **kwargs)
        return wrapped
    wrapped = wrapper(problema, 2, 100)
    veces = 10
    print("{:.5f} seg por loop".format(timeit(wrapped, number=veces) / veces))
    print("resultado: {}".format(problema(2, 100)))
    # 1.34389 seg por loop
    # resultado: 9183

    def wrapper_p(problema_pythonico, *args, **kwargs):
        def wrapped():
            return problema_pythonico(*args, **kwargs)
        return wrapped
    wrapped = wrapper_p(problema_pythonico, 2, 100)
    veces = 10
    print("{:.5f} seg por loop".format(timeit(wrapped, number=veces) / veces))
    print("resultado: {}".format(problema_pythonico(2, 100)))
    # 0.01556 seg por loop
    # resultado: 9183
