sans doute cette fonction existe déjà dans une lib, si vous la connaissez ...
écrire une fonction mrange(start,stop,length,type=None):
retourne une liste de step length valeurs comprises entre start et stop (inclus) type(falcutatif) force le type des valeurs retournées et indique si ceux sont des int ou des float
exemple:
cette fonction me sert à déplacer des sprites en lignes droites, à faire des dégradés de couleurs, etc ...
par exemple du noir au blanc en 10 niveaux de gris:
def mrange(start,stop,step,type_=None):
if hasattr(start,'__iter__'): return list(zip(*[mrange(x,y,step,type_) for x,y in zip(start,stop)]))
v = (stop-start)/(step-1.)
if (not type_ and type(stop-start) is int) or (type_ is int): return [int(round(v*i+start)) for i in range(step)]
return [v*i+start for i in range(step-1)]+[float(stop)]
J'ai très bien lu le message fred1599 (et accessoirement josmiley), tu n'as visiblement pas compris mon interrogation. Je trouve simplement plutôt étrange de vouloir reproduire une fonction en utilisant les mêmes paramètres avec les mêmes noms, mais de changer le fonctionnement de l'un d'eux en utilisant un nom qui ne reflète pas du tout son but.
Après, si c'est voulu pour je-ne-sais quelle raison, il suffit de le dire. Je trouve simplement que c'est complètement contre-intuitif et ça peut porter à confusion.
Je propose une solution un peu moche mais qui a l'air de marcher. Par contre je ne fais aucun test sur les paramètres, donc si on passe n'importe quoi ça va donner n'importe quoi
Je mets le code et la petite explication en secret.
def mrange(start,stop,length,t=int):
def _mrange(start,stop,length,t=int):
if t == int:
t = round
L,step,dif = [],(stop-start)/(length-1),0
while len(L) < length:
L.append(t(start + dif))
dif += step
return L
if type(start) == int:
return _mrange(start,stop,length,t)
return list(zip(*(_mrange(b,e,length,t) for b,e in zip(start,stop))))
En gros je me sers de la fonction du type passé en argument, et dans le cas d'un int je remplace par round. Je détermine le pas avec <math>\(\frac{\text{stop}-\text{start}}{\text{length}-1}\)</math> et je mets la différence entre la valeur de départ et la valeur actuelle dans dif, bien que ça serait aussi simple de changer la valeur start. Dans le cas où start et stop sont des entiers, je renvoie simplement le résultat de la sous-fonction, sinon, je considère que ce sont des tuples. Dans ce cas je me sers de zip pour d'abord transformer par exemple (0,0,0),(255,255,255) en (0,255),(0,255),(0,255), que je passe ensuite à ma sous-fonction, et pour finir, je me ressers de zip pour transformer le résultat du type [[0,28,...,255],[0,28,...,255],[0,28,...255]] en [(0,0,0),(28,28,28),...,(255,255,255)]
Shaddan, c'est à quelques choses près ce que j'ai fait, ça fonctionne comme il faut(sauf sous python2).
Par contre et c'est ma faute car mal expliqué dans l'énoncé, l'argument type sert à forcer la type retourné ... j'édite l'énoncé.
Je n'ai pas tout à fait respecté l'énoncé.
J'ai remplacé l'argument type par le nombre de décimal (ndigit). Ça m'a semblé plus pratique.
Ainsi, si ndigit est nul ou négatif, les résultats seront des entiers, sinon des décimaux arrondis à ndigit après la virgule.
Code rectifié.
def mrange(start, stop, length, typ_=None):
gen = lambda a, b, c: ( a + b * i for i in range(c) )
if hasattr(start, '__iter__'):
for t in zip(*[ mrange(a, b, length, typ_)
for a, b in zip(start, stop) ]):
yield t
else:
step = (stop - start) / (length - 1)
if (typ_ is None and type(start) is int and type(stop) is int) \
or typ_ is int:
for n in gen(start, step, length):
yield round(n)
else:
for n in gen(start, step, length):
yield n
merci de participer PsycoPy,
le code de Shaddan est pour le moment était le plus rapide ... (j'ai éditer le mien )
désolé PsycoPy, ton code est 2x moins rapide que celui de Shaddan.
Shaddan, c'est à quelques choses près ce que j'ai fait, ça fonctionne comme il faut(sauf sous python2).
Par contre et c'est ma faute car mal expliqué dans l'énoncé, l'argument type sert à forcer la type retourné ... j'édite l'énoncé.
En effet, j'ai complètement oublié de préciser que c'était du Python 3.x, désolé.
Pour ce qui est du type retourné, round sans 2ème argument retourne un int donc je ne pense pas qu'il y ait de problème avec mon code à ce niveau là, si ?
Par contre j'avoue que j'avais pas pensé à faire un appel récursif plutôt que de créer une sous-fonction. L'appel récursif me parait quand même plus malin.
Citation : GurneyH
Juste un truc, le [débutant] dans la titre de l'exercice, me semble un peu sous estimé, non?
Il faut déjà une certaine maitrise en Python, je crois.
Je suis d'accord que ça serait peut-être mieux de mettre au moins débutant/intermédiaire. Il faut au moins connaître à peu près les listes et les tuples, et savoir se servir un minimum de la librairie standard (si on veut ne pas trop galérer) donc pour un vrai débutant ça me parait compliqué.
Personnellement je comprends jamais rien aux benchmarks de Python.
Leur intérêt ou leur fonctionnement ?
Pour ce qui est de l'intérêt... bah il n'y en a pas vraiment, mais c'est sympa de voir les différence de perfs d'un algo à l'autre.
Puisqu'on en parle :
# -*- coding:utf-8 -*-
from __future__ import print_function
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
# josmiley :
def josmiley_mrange(start, stop, step, type_=None):
if hasattr(start,'__iter__'):
return list(zip(*[ josmiley_mrange(x, y, step, type_) for x, y in zip(start, stop) ]))
elif type_ is None and type(start) is int and type(stop) is int:
type_ = int
v = (stop-start) / (step-1.)
return ([ int(round(v * i + start)) for i in range(step) ]) if type_ is int else ([ v * i + start for i in range(step) ][:-1] + [float(stop)])
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
# PsycoPy :
def PsycoPy_mrange(start, stop, length, type_=None):
if hasattr(start, "__iter__"):
return zip(*( PsycoPy_mrange(a, b, length, type_)
for a, b in zip(start, stop) ))
else:
step = (stop - start) / (length - 1)
if type_ is int or (type_ is None and type(start) is int and type(stop) is int):
return ( round(start + step * i) for i in range(length) )
else:
return ( start + step * i for i in range(length) )
###############################################################################
################################# Benchmark ###################################
###############################################################################
if __name__ == "__main__":
from timeit import Timer
print("\n[mrange] Benchmark")
players = (
"josmiley",
"PsycoPy"
)
arguments = (
"(0, 39657, 7)",
"(0, 39657, 70000)",
"(1453, 10, 100, float)",
"(10.6, 9000.9, 42)",
"(10.6, -9000.9, 50450, int)",
"((32.2, 5), (32.5, -247), 54321)",
"((123, 456), (-1234, -4567), 123, float)"
)
def test(funct, args):
for _ in funct(*args):
pass
repeat = 50
stmt = "test({}_mrange, {})"
setup = "from __main__ import test, {}_mrange"
mrange = josmiley_mrange # fonction désignée comme étant valide
scores = []
for name in players:
print()
ls = []
for args in arguments:
print(name, "_mrange", args, sep='')
# Tester si la fonction retourne bien le resultat attendu
# (par rapport à la fonction mrange désignée comme valide) :
s = "list(mrange" +args+ ") == list(" +name+ "_mrange" +args+ ')'
if eval(s):
t = Timer(stmt.format(name, args),
setup.format(name)).timeit(repeat)
print('\t', t, " seconde", 's' if t > 1 else '', sep='')
ls.append(t)
else:
print("\tERROR : resultat incorrect !")
break
else:
t = sum(ls)
print("Total : ", t, " seconde", 's' if t > 1 else '', sep='')
scores.append((t, name))
print("\nPodium")
scores.sort()
for i, t in enumerate(scores):
print(i + 1, '> ', t[1].rjust(25), ' : ', t[0],
" seconde", 's' if t[0] > 1 else '', sep='')
À noter que les deux algos présenté ici sont totalement identique.
Nan, ce que je voulais dire c'est que autant en C ou dans d'autres langages, en général on a un benchmark plus ou moins proche de ce à quoi on pourrait s'attendre, autant en Python ça dépend vraiment des fois
Un code censé faire, théoriquement, deux fois plus de calculs qu'un autre pourrait être plus rapide, ça ne m'étonnerait pas plus que ça.
Dans mon code, le problème venait de la dernière valeur renvoyée : au lieu de renvoyer stop, je renvoyais une valeur calculée qui, théoriquement devait être égale à stop, mais les float ne sont pas assez précis, la valeur retournée était légèrement différente.
Correction :
J'ai juste modifié une valeur dans ma lambdagen et ajouté un yield à la fin.
Du coup, je dois même gagner en perf...
def mrange(start, stop, length, typ_=None):
gen = lambda a, b, c: ( a + b * i for i in range(c - 1) )
if hasattr(start, '__iter__'):
for t in zip(*[ mrange(a, b, length, typ_)
for a, b in zip(start, stop) ]):
yield t
else:
step = (stop - start) / (length - 1)
if (typ_ is None and type(start) is int and type(stop) is int) \
or typ_ is int:
for n in gen(start, step, length):
yield round(n)
else:
for n in gen(start, step, length):
yield n
yield stop
C'est ça, qui m'a arrêté.
Pas si simple de spécifier les valeurs attendues.
Lorsque tu dis
Citation : Josmiley
on doit obtenir:
Tu te bases sur quoi?
Les résultats de ton code?
retourne une liste de length valeurs comprises entre start et stop (inclus)
ce n'était pas précisée mais les valeurs doivent être équidistantes les unes des autres (hormis les aléas des float)
ben, si ça répond pas à l'énoncé, c'est pas bon ...
Hum, en effet étant donné que dans mon code le type par défaut est int, il faut rajouter une condition pour vérifier le type des variables passés en paramètres.
J'ai pas testé mais à mon avis avec ça ça devrait passer.
def mrange(start,stop,length,t=int):
def _mrange(start,stop,length,t=int):
t = float if float in {t,type(start)} else round
L,step,dif = [],(stop-start)/(length-1),0
while len(L) < length:
L.append(t(start + dif))
dif += step
return L
if type(start) == int:
return _mrange(start,stop,length,t)
return list(zip(*(_mrange(b,e,length,t) for b,e in zip(start,stop))))
mon code est faux aussi, en effet pour le type float, mathématiquement a/b*c et (a*c)/b renvoient le même résultat ... ben non.
mon new code:
def mrange(start,stop,step,type_=None):
if hasattr(start,'__iter__'): return list(zip(*[mrange(x,y,step,type_) for x,y in zip(start,stop)]))
s,v = stop-start,step-1.
if (not type_ and type(s) is int) or (type_ is int): return [int(round((s*i)/v+start)) for i in range(step)]
return [(s*i)/v+start for i in range(step)]
on gagne en précision de calcul mais on perd en performance.
Non sans mal.
Je n'ai pas insisté plus que ça sur la précision, et je n'ai pas comparer la sortie avec les code précédents.
def mrange(start, end, length, type_ = None):
if hasattr(start, '__iter__'):
return zip(*[mrange(a, b, length, type_)for a, b in zip(start, end)])
if start > end:
start_, end_ = end, start
else:
start_, end_ = start, end
ret, step = [], float(end_ - start_) / (length - 1)
if type(start) is int and type(end) is int and type_ is None:
type_ = int
while start_ < end_:
if type_ is int:
ret.append(int(round(start_)))
else:
ret.append(float(start_))
start_ += step
ret.append(end_)
if start < end:
return ret
else:
return list(reversed(ret))
J'ai une question!
Cette ligne
return list(reversed(ret))
Je l'ai bricolé car
return ret.reverse()
me retourne None.
C'est surement stupide, mais je ne vois pas le problème.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.