Je ne pense pas que passer deux fois sur le tableau soit un problème. Considérez le pseudo-code suivant :
minval = array[0]
maxval = array[0]
for i in array:
if i < minval:
minval = i
if i > maxval:
maxval = i
Bien qu'il n'y ait qu'une seule boucle ici, il y a toujours deux contrôles. (Au lieu d'avoir 2 boucles avec 1 contrôle chacune). La seule chose que vous économisez vraiment est l'overhead d'une boucle. Si les tableaux sont vraiment grands comme vous le dites, cette surcharge est faible par rapport à la charge de travail de la boucle réelle. (Notez que tout ceci est implémenté en C, donc les boucles sont plus ou moins gratuites de toute façon).
EDIT Désolé pour les 4 d'entre vous qui ont voté et ont eu confiance en moi. Vous pouvez définitivement optimiser ceci.
Voici du code fortran qui peut être compilé dans un module python via f2py
(peut-être un Cython
Un gourou peut venir et comparer avec une version C optimisée...) :
subroutine minmax1(a,n,amin,amax)
implicit none
!f2py intent(hidden) :: n
!f2py intent(out) :: amin,amax
!f2py intent(in) :: a
integer n
real a(n),amin,amax
integer i
amin = a(1)
amax = a(1)
do i=2, n
if(a(i) > amax)then
amax = a(i)
elseif(a(i) < amin) then
amin = a(i)
endif
enddo
end subroutine minmax1
subroutine minmax2(a,n,amin,amax)
implicit none
!f2py intent(hidden) :: n
!f2py intent(out) :: amin,amax
!f2py intent(in) :: a
integer n
real a(n),amin,amax
amin = minval(a)
amax = maxval(a)
end subroutine minmax2
Compilez-le via :
f2py -m untitled -c fortran_code.f90
Et maintenant nous sommes dans un endroit où nous pouvons le tester :
import timeit
size = 100000
repeat = 10000
print timeit.timeit(
'np.min(a); np.max(a)',
setup='import numpy as np; a = np.arange(%d, dtype=np.float32)' % size,
number=repeat), " # numpy min/max"
print timeit.timeit(
'untitled.minmax1(a)',
setup='import numpy as np; import untitled; a = np.arange(%d, dtype=np.float32)' % size,
number=repeat), '# minmax1'
print timeit.timeit(
'untitled.minmax2(a)',
setup='import numpy as np; import untitled; a = np.arange(%d, dtype=np.float32)' % size,
number=repeat), '# minmax2'
Les résultats sont un peu stupéfiants pour moi :
8.61869883537 # numpy min/max
1.60417699814 # minmax1
2.30169081688 # minmax2
Je dois dire que je ne le comprends pas complètement. Comparer juste np.min
contre minmax1
et minmax2
est toujours une bataille perdue, donc ce n'est pas seulement un problème de mémoire ...
notes -- Augmentation de la taille par un facteur de 10**a
et en diminuant la répétition par un facteur de 10**a
(en maintenant la taille du problème constante) modifie effectivement les performances, mais pas de manière apparemment cohérente, ce qui montre qu'il existe une certaine interaction entre les performances de la mémoire et le surcoût des appels de fonction dans Python. Même en comparant un simple min
L'implémentation en fortran bat celle de numpy par un facteur d'environ 2 ...