na pomysł, aby używać tylko itertools
z krotki (2,3,4), na przykład:
mieć wiele iloczyn kartezjański:
(2,),(3,),(4,) # repeat 1
(2, 2), (2, 3), (2, 4), (3, 2), (3, 3), (3, 4), (4, 2), (4, 3), (4, 4) # repeat 2
...
Dla każdego z tym krotki użyć reduce
z operator.mul
i wartość początkowa 1 pomnożyć je:
reduce(operator.mul, tuple, 1)
to, otrzymując mnożenia dla produktu, poziom 2 kartezjańskie w:
[reduce(operator.mul,t,3) for t in itertools.product((1,2,3),repeat=2)]
>>>[3, 6, 9, 6, 12, 18, 9, 18, 27]
Teraz musimy zwiększyć repeat
aż do spełnienia warunku zatrzymania, na przykład: każde mnożenie przyniesie wynik większy niż top
. Ponieważ wartość samlesta, która się liczy, to 2
(ponieważ 1
razy 1
wiele razy jest tylko 1, więc nie będzie liczyć) możemy pomnożyć 2 razy x, podczas gdy jest niższa niż top
.Więc: top/2 = x
oznacza, że możemy iterację range(1,top/2)
:
[reduce(operator.mul,t,1) for c in range(1,10/2) for t in itertools.product((1,2,3),repeat=2) if reduce(operator.mul, t, 1) < 10]
To przynoszące powtarzające się wartości, więc niech przekształcić je w zestawie:
set([reduce(operator.mul,t,1) for c in range(1,10/2) for t in itertools.product((1,2,3),repeat=2) if reduce(operator.mul, t, 1) < 10])
Korzystanie tylko itertools
może być kłopotliwe dla tego, ale rozwiązanie wydaje się ładne. Jestem pewien, że można go zoptymalizować, wprowadzając lepszy warunek zatrzymania. Ostateczny kod będzie wyglądać następująco:
UWAGA: Istnieje twierdzenie o liczbach pierwszych, które pozwalają zoptymalizować stan zatrzymania do math.sqrt(top)
import math
def f(t,m):
return set([reduce(operator.mul, t1, 1) for c in range(1,int(math.sqrt(m)) for t1 in itertools.product(t,repeat=c) if reduce(operator.mul,t1,1) < m])
f((2,3,4),10)
>>>set([2, 3, 4, 6, 8, 9])
Nadziei to może dać inny pomysł :)
Algorytm Zero Piraeusa jest nie mniej elegancki, ale ten wydaje się szybszy. Dziękuję ludziom !! –