2016-04-18 10 views
5

Ho scritto un semplice liner in julia per risolvere un piccolo problema di matematica: trovare un numero a due cifre, A e un numero a tre cifre B tale che il loro prodotto , A x B è un cinque numeri a due cifre e ogni cifra da 0 a 9 appare esattamente una volta tra i numeri A, B e A x B. Per esempio,Ottimizzazione di un julia one-liner per renderlo veloce come il pitone

54 x 297 = 16,038 

Ecco il mio codice julia che trova tutte le possibili soluzioni:

println(filter(l -> length(unique(reduce(vcat, (map(digits, l))))) == 10, [[x, y, x*y] for x in Range(10:99), y in Range(100:999)])) 

si risolve il problema, ma poi ho provato in python e si avvicinò con questo:

print filter(lambda y: len(set(''.join([str(x) for x in y])))==10, [[x, y, x*y] for x in range(10, 99) for y in range(100, 999)]) 

Timing entrambi, sono stato sorpreso di scoprire che il codice Python è stato eseguito più di due volte più veloce del codice julia. Qualche suggerimento per un approccio più veloce per il codice julia (preferibilmente tenendolo a un solo liner)?

parte: so di poter migliorare sia con un rapido ritocco delle gamme dirange(12, 98)erange(102, 987).

Aggiornamento

Andando oltre one-liners, ho preso il consiglio che loop può essere più veloce di liste, per cui ho confrontato le seguenti alternative:

Julia

ans = Array{Tuple{Int32, Int32, Int32}}(0) 
for x in 12:98 
    for y in 102:987 
    if length(unique(digits(x+y*100+x*y*100_000)))==10 push!(ans, (x, y, x*y) end 
    end 
end 
println(ans) 

Python

ans = [] 
for x in range(12,98): 
    for y in range(102,987): 
    if len(set(str(x+y*100+x*y*100000)))==10: 
     ans.append((x, y, x*y)) 
print ans 

Il codice Python viene eseguito molto più velocemente (anche se cambio il codice per entrambi per stampare semplicemente i risultati nel ciclo piuttosto che raccoglierli in un elenco). Mi aspettavo prestazioni migliori da Julia.

Inoltre, nel caso in cui si è interessati, l'elenco completo delle soluzioni è

39 x 402 = 15,678 
27 x 594 = 16,038 
54 x 297 = 16,038 
36 x 495 = 17,820 
45 x 396 = 17,820 
52 x 367 = 19,084 
78 x 345 = 26,910 
46 x 715 = 32,890 
63 x 927 = 58,401 
+0

Stavo cronometrando questi con 'time' sulla riga di comando. L'uso di '@ time' in julia e' timeit' in python suggerisce che il codice python sia solo del 65% più veloce piuttosto che più del doppio, ma questa è comunque una differenza significativa. – seancarmody

+4

sostituisci semplicemente '[x, y, x * y]' a '(x, y, x * y)' può ottenere un miglioramento del 30%. Puoi anche sostituire 'Range (10:99)' con '10: 99' per accorciare il tuo codice. –

+0

Grazie. È interessante notare che il passaggio a tuple anziché a liste offre un miglioramento significativo per Julia, ma è trascurabile per Python. – seancarmody

risposta

5

@simd for x in 10:99 for y in 100:999 length(unique(digits(x+y*100+x*y*100_000)))==10 && println(x,'*',y,'=',x*y) end end

nel mio computer questo codice è di circa 3 volte la velocità dell'origine uno. (0,223902 secondi vs 0,680781 secondi)

La chiave è "avoid unnecessary arrays". Utilizzare for loop o tuple quando possibile

+0

Bella soluzione, ho una domanda ... qual è lo scopo di @simd su questo esempio e come fai a sapere quando usarlo? – Esteban

+0

@Esteban Proviene da [julia doc] (http://docs.julialang.org/en/release-0.4/manual/performance-tips/#performance-annotations), ma per essere onesto, in questo esempio, si tratta di un piccolo miglioramento –

+0

Grazie per il suggerimento - decisamente più veloce. È interessante notare che ho anche modificato il codice Python in modo simile a usare i loop piuttosto che gli array e il risultato è significativamente più veloce del codice julia. Certo, il requisito di formattazione degli spazi vuol dire che il codice python è di quattro righe, non uno. – seancarmody

Problemi correlati