Creo que para solucionar este problema no es necesario ningún bucle.
Esta es la solución más simple que he podido encontrar:
from __future__ import division
def sumar_multiplos_k(a1, an,d):
n = an/d
S = ((a1+an)/2)*n
return S
print(sumar_multiplos_k(3,999,3)+sumar_multiplos_k(5,995,5)-sumar_multiplos_k(15,990,15))
El razonamiento es el siguiente:
Viendo la naturaleza del problema, tiene una pinta de progresión
aritmética que echa para atrás. Al final es encontrar la suma de los
múltiplos de 3 o de 5, es decir, suma de series cuyos elementos están
separados entre tres o cinco unidades, es decir, con razón 3 o 5.
La expresión de la progresión aritmética es:
((a1+an)/2)*n donde a1 es el primer elemento de la serie, an es el
último elemento de la serie y n el número total de elementos.
En esta expresión lo único que podemos desconocer es n, el número
total de elementos, pero si vamos a la expresión general de la
progresión podemos decir que
an = a1+(n-1)d donde a1 es el primer elemento, n el número total de
elementos y d la razón de la serie, es decir el número que debemos
sumar al elemento anterior para conseguir el próximo elemento.
De la expresión anterior tenemos todos los parámetros excepto n así
que se convierte es simplificar y resolver una ecuación de primer
grado.
El "quid" de la cuestión, creo yo, es en darse cuenta de lo siguiente:
Álgunos múltiplos de 3:
3,6,9,12,15,...,27,30,33,...,42,45,...
Algunos múltiplos de 5:
5,10,15,20,25,30,35,40,45,...
Si observamos 15,30,45 se repiten en ambas series por lo que si
sumasemos ambas progresiones estaríamos sumando los múltiplos de 15
dos veces. Por lo que a la suma de la progresión de 3 y la progresión
de 5 hay que restarle la progresión de 15. Y ese sería el resultado.
No he encontrado una forma más óptima de hacerlo, de esta forma nos
quitamos de encima los bucles y no hay que buscar optimizaciones con
cython ni nada parecido.
Saludos!
On Wed, 5 Sep 2018 at 06:55, AGTUGO wrote:
>
> Después de ver los tiempos de ejecución obviamente aquellos métodos que
> hicieron un for pues fueron más lentos, los que generaron los números para
> ser sumados pues son los más rápidos, lo cual no es ninguna sorpresa. Creo
> que la mayoría de la gente no busca velocidad en python pero hay casos donde
> optimizaciones pequeñas hacen la diferencia, al final creo que lo mejor para
> optimizar pues es escribir en c o en cython algunas funciones en particular.
> Creo que mucho más fácil de mantener en cython. Prepararé una comparación de
> todos los métodos aquí expuestos en cPython, pypy, adicionalmente numoy y
> cython, para cerrar esta discusión y tratar de llegar a algo que pueda ser
> referenciado en el futuro.
>
> On Tue, Sep 4, 2018 at 10:10 PM AGTUGO wrote:
>>
>> Adicionalmente me gusta verlo como conjuntos A union B.
>>
>> def euler001_with_sets(n: int, multiples:Tuple[int]) -> int:
>> union_set = set()
>> all_sums_set = (set(range(0,n,mul)) for mul in multiples)
>> union_set = union_set.union(*all_sums_set)
>> return sum(union_set)
>>
>>
>>
>> On Tue, Sep 4, 2018 at 9:35 AM AGTUGO wrote:
>>>
>>> Aquí lo único que haría para cualquier caso es sacar la comparación en una
>>> funciòn para que no este tan hardcoded
>>>
>>> from typing import List, Tuple
>>>
>>> begin = 0
>>> end = 1000
>>> multiples= (3,5)
>>>
>>> """
>>> Esta función revisa si es divisible entre todos los multiplos propuestos
>>> dentro del mundo
>>> de los naturales y retorna un booleano en caso de que así sea
>>> """
>>> def is_divisible(tb_divided:int, multiples: List[int]) -> bool:
>>> return any((tb_divided%mul == 0 for mul in multiples))
>>>
>>> def euler001(n: int, multiples:Tuple[int]) -> int:
>>> return sum(i for i in range(1, n) if is_divisible(i,multiples))
>>>
>>> print(euler001(end, multiples))
>>>
>>>
>>>
>>> On Tue, Sep 4, 2018 at 5:33 AM Chema Cortes wrote:
El lun., 3 sept. 2018 a las 21:12, AGTUGO () escribió:
>
> """
> Problema tomado de
> https://projecteuler.net/problem=1
>
>
> If we list all the natural numbers below 10 that are multiples
> of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
> Find the sum of all the multiples of 3 or 5 below 1000.
>
> Si listamos todos los numeros naturales menores a 10 que son
> múltiplos de 3 o 5 obtenemos 2, 5, 6 y 9. La suma de los múltiplos es 23.
> Encuentra la suma de los múltiplos de 3 o 5 menores de 1000.
>
>
> """
>
> """
> Este es mi aporte de código no esta diseñado para ser eficiente,
> el objetivo es jugar con el lenguaje. Ojalá puedan compartir
> una visión interesante de como resolver este problema.
> Si tienen una forma más eficiente de hacer el set o más elegante también
> es bienvenido.
> Saludos.
> """
>
> import itertools
> begin = 0
> end = 1000
> multiples= (3,5)
>
> x = [range(begin,end,i) for i in multi