IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Opérations arithmétiques sur les Listes


Sujet :

Python

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    Points : 67
    Points
    67
    Par défaut Opérations arithmétiques sur les Listes
    Bonjour,

    J'ai appris (depuis peu ) que sur les listes on pouvait "opérer" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    >>> L=[1,3,6,2,5,12]
    >>> max(L)
    12
    >>> min(L)
    1
    >>> Sum(L)
    29
    D'où ma question : existe-t-il l'équivalent pour le produit ?
    J'ai essayé
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    >>> L=[]
    >>> dir(L)
    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
    Et je n'y vois même pas le sum, alors le produit...

    J'ai essayé du côté des list comprehension et je n'arrive à rien...

    Faut-il construire de toutes pièces cette fonction qui donnerait le produit de tous les éléments numériques d'une liste ou bien existe-t-elle de base dans Python (comme sum) et quelle est sa "syntaxe" ?

    Merci d'avance.

    @+

  2. #2
    Membre éclairé
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Points : 773
    Points
    773
    Par défaut
    Je ne crois pas qu'une telle fonction existe (en tout cas pas en en builtin), mais un petite fonction est facile à réaliser
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    def product(iterable):
        res=1
        for x in iterable:
            res*=x
        return res
    Ensuite il est normal que tu n'ait pas trouver sum dans les méthode associées aux objets listes, c'est une fonction qui prend en paramètre un objet iterable (liste, tuple, generator, iterator etc...)

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    Points : 67
    Points
    67
    Par défaut
    Déjà ?

    Waow !!
    Grand merci donc, mes recherches ne donnant rien, je m'étais résolu à la bâtir moi-même...
    Et j'étais arrivé à la même solution que toi.
    Maintenant, la question est : peut-on encore "compresser" ce code, pourtant déjà fort succinct ?

    @+

  4. #4
    Expert éminent sénior
    Avatar de Guigui_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2002
    Messages
    1 864
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2002
    Messages : 1 864
    Points : 10 067
    Points
    10 067
    Par défaut
    avec reduce:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    >>> reduce(lambda x, y: x *y, range(1, 10))
    362880
    Pour info, avec NumPy, tu as la fonction toute faite:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    import numpy
    a = numpy.array(range(1, 10))
    a.prod() ## 362880

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    Points : 67
    Points
    67
    Par défaut
    Salut guigui,

    Merci !
    J'ai essayé de faire avaler une liste à ta ligne au lieu de range(1,10) : pas trouvé.
    Peut-on le faire ?
    En attendant, je me rabats sur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    >>> L=[1,3,6,2,5,12]
    >>> def prod(x,y) : return x*y
    >>> reduce(prod,LL)
    ## 2160
    Je vais voir numpy.

    @+

    [Edit] numpy n'est pas présent nativement dans Python ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Traceback (most recent call last):
      File "<pyshell#23>", line 1, in <module>
        import numpy
    ImportError: No module named numpy
    Rectification : ton utilisation de reduce fonctionne avec ma liste :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     >>> L=[1,3,6,2,5,12]
    >>> reduce(lambda x, y: x *y,L)
    ## 2160
    Merci encore

  6. #6
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 76
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Points : 1 913
    Points
    1 913
    Par défaut
    reduce est très bien et très utile. Il y a cependant une petite précaution à prendre.
    Lorsque l'argument est une liste vide vide, python ne sait que faire et renvoit une erreur. Pour les humains la chose est claire quand la liste est vide il faut retourner le neutre de l'opération.
    En résumé, toujours penser à traiter le cas de la liste vide.
    Je confirme que ni numpy ni scipy ne font partie de la distribution standard.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  7. #7
    Membre éprouvé

    Profil pro
    Inscrit en
    Août 2004
    Messages
    723
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 723
    Points : 923
    Points
    923
    Par défaut
    Pour échapper au cas liste vide, on peut fournir un premier opérande comme troisième argument :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    >>> L = [2, 3, 4]
    >>> def prod(x, y): return x*y
    ... 
    >>> reduce(prod, L, 1)
    24
    >>> reduce(prod, L, 2)
    48
    >>> reduce(prod, [])
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: reduce() of empty sequence with no initial value
    >>> reduce(prod, [], 1)
    1

  8. #8
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 76
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Points : 1 913
    Points
    1 913
    Par défaut
    Pour échapper au cas liste vide, on peut fournir un premier opérande comme troisième argument :
    Bon à savoir , merci!
    Donc si c'est une somme tu passes 0 en troisième argument.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  9. #9
    Membre éclairé
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Points : 773
    Points
    773
    Par défaut
    Citation Envoyé par oiffrig Voir le message
    Pour échapper au cas liste vide, on peut fournir un premier opérande comme troisième argument :
    C'est ce que je m'était dis, mais faire le produit d'une liste vide ne doit-il pas être 0 ? auquel cas j'hésite entre une condition qui vérifie la longueur de l'objet itérable, ou un clause try/except TypeError plus rapide dans le cas de longues liste, mais moins fiable cause passer une liste de chaines en argument retournerait également 0
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    def prod1(itr):
        def p a,b: return a*b
        try: return reduce(p, itr)
        except: return 0
     
    def prod2(itr):
        def p a,b: return a*b
        if len(itr)!=0: return reduce(p,itr)
        else: return 0
     
    #troisième soluce, mais je sais pas ce que ça vaut
    def prod3(itr):
        def p a,b: return a*b
        if str(itr)[1:-1]: return reduce(p,itr)
        else: return 0
    def prod3

  10. #10
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 462
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 462
    Points : 9 249
    Points
    9 249
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    On peut aussi renvoyer None lorsque le résultat n'a pas de sens, au lieu de déclencher une exception. Cela nécessite un test sur le résultat, mais c'est moins violent qu'une exception.

    Cependant, pour renvoyer None, il faut faire un test sur le paramètre donné à la fonction. Voilà une solution possible en une seule ligne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    prod = lambda z : (len(z)==0 and [None] or [reduce(lambda x,y : x*y, z)])[0]
    Application:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    L = [1,5,7,3,2,9,4,6]
    print prod(L)
    45360
    print prod([])
    None
    A noter qu'on peut utiliser cela pour calculer les factorielles en une seule ligne, y compris avec un test sur le paramètre passé:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    fact = lambda z : (z<0 and [None] or [reduce(lambda x,y : x*y, range(1,z+1),1)])[0]
    print fact(6)
    720
    print fact(0)
    1
    print fact(-5)
    None
    Mais d'après mes tests, cette manière de calculer les factorielles ne donne aucun avantage de temps d'exécution par rapport à la fonction équivalente. De ce fait, je préfère tout de même la version "fonction" dont le code est plus clair.

    Tyrtamos
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  11. #11
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    Points : 67
    Points
    67
    Par défaut
    Bonjour à tous,

    Python est magique ! Et vos contributions sont des merveilles d'orfèvrerie...
    Je vous propose cependant une petite suggestion pour contourner le problème.

    Et si on évitait de transmettre une liste vide ? Il suffirait d'intervenir en amont et de ne pas, par exemple, appeler :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    reduce(lambda x, y: x *y, L])
    quand L est vide et donc de tester cet état en amont avec le if len(L)==0.
    Toutefois, ça ne résout pas le problème de 0! ou comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    >>> for n in range(10):
    	factorielle=reduce(lambda x, y: x *y, xrange(1,n+1+(1-n)*(n<2)))
    	print str(n)+"! =",factorielle
     
     
    ## 0! = 1
    ## 1! = 1
    ## 2! = 2
    ## 3! = 6
    ## 4! = 24
    ## 5! = 120
    ## 6! = 720
    ## 7! = 5040
    ## 8! = 40320
    ## 9! = 362880
    Cordialement,

    @+

    Un chti clin d'oeil à Zavonen mien collègue à double titre : prof de maths retraité... Mais il en sait beaucoup plus que moi...

  12. #12
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 76
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Points : 1 913
    Points
    1 913
    Par défaut
    C'est ce que je m'était dis, mais faire le produit d'une liste vide ne doit-il pas être 0 ?
    Ah que non !
    Un opérateur sur une famille vide doit toujours donner le neutre de l'opération en question..
    Et il y a une logique derrière.
    Il faut bien que Op(L1)OpOp(L2) donne Op(L1+L2) si la loi est associative, ce qui oblige Op(Nul)= neutre
    Donc si on fait un reduce d'un produit il faut donner la valeur 1 quand la liste est vide de la même façon que 0!=1 et x^0=1, parce que 1 est le neutre de la multiplication.
    Salut à mon collègue Yoshik. Bienvenue au club des vétérans. Au fait je ne connais pas le sens de ton pseudo mais en russe yojik signifie 'petit hérisson' sympa, non ?
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  13. #13
    Membre éclairé
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Points : 773
    Points
    773
    Par défaut
    Il faut bien que Op(L1)OpOp(L2) donne Op(L1+L2) si la loi est associative, ce qui oblige Op(Nul)= neutre
    Ok, je comprends qu'un produit d'une liste vide dans ce contexte doit être 1. Mais une question me taraude alors : pour l_v une liste vide et l_e une liste d'entier [1,2,3], produit(l_v)+somme(l_e) retournerait 7, ça me fait bizarre (p'têt parce que ça semble pas très naturel...)... ça voudrait dire que que quelque soit le contexte, un produit sera toujours différent de 0 ? Une liste vide (liste de rien) ne peut donc assimilée à une liste constituée d'un 0 (un rien) ?

    EDIT : Je sens que le lien de ta signature va sûrement être très utile

  14. #14
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    Points : 67
    Points
    67
    Par défaut
    Zdrass'tié Tovarich Zavonen,

    Ia rad kogda ia ponimaillou...
    Et là, je comprends ton point de vue : mais j'ai vu dans une autre discussion une "chamaillerie" sur la notion de "vecteur", apparemment différente en informatique de son acception mathématique. Alors cette vérité mathématique est-elle aussi une vérité informatique ? Pour moi oui, mais ce n'est qu'un avis que je partage avec toi...
    [Mode HS]
    Quant à mon pseudo, lorsque j'ai voulu créer un adresse mél non professionnelle le Yoshi m'a été refusé et j'ai donc rajouté la lettre suivante du nom Yoshikawa, de Eiji Yoshikawa auteur de "La pierre et le Sabre" et "La parfaite Lumière".
    Cela dit, petit hérisson me convient bien : naguère et à plusieurs reprises, mon style d'écriture fut qualifié d'"urticant"...
    [/Mode HS]

    Pour revenir à ma proposition de ligne de calcul, c'est vrai qu'elle n'est pas aussi claire qu'une bonne vieille fonction (m'enfin le lambda n'est pas la mer à boire) et je suis prêt presque à parier qu'elle est moins rapide à cause de lambda x, y, x *y.
    Je viens d'essayer 100000! 37 s contre 35 s chez moi, rien de fondamental donc...

    @+

    [EDIT]
    Une liste vide (liste de rien) ne peut donc assimilée à une liste constituée d'un 0 (un rien) ?
    D'un point de vue mathématique, pour moi non...
    0 n'est pas "rien", c'est le nombre d'éléments de l'ensemble vide. En notation mathématique : Card({})=0 et Card({0})=1...
    D'ailleurs len([]) donne 0 et len([0]) renvoie 1.
    L'ensemble des parties d'un ensemble, n'est pas vide, car il contient toujours au moins l'ensemble vide et son cardinal vaut 1 minimum.
    len([[]]) renvoie 1.
    Voyons ce que va dire Zavonen...

  15. #15
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 76
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Points : 1 913
    Points
    1 913
    Par défaut
    D'un point de vue mathématique, pour moi non...
    0 n'est pas "rien", c'est le nombre d'éléments de l'ensemble vide. En notation mathématique : Card({})=0 et Card({0})=1...
    D'ailleurs len([]) donne 0 et len([0]) renvoie 1.
    L'ensemble des parties d'un ensemble, n'est pas vide, car il contient toujours au moins l'ensemble vide et son cardinal vaut 1 minimum.
    len([[]]) renvoie 1.
    Voyons ce que va dire Zavonen...
    Pravilna, Ia soglacen !!!
    200% d'accord.
    quelque soit le contexte, un produit sera toujours différent de 0
    Non un produit est nul quand il n'est pas vide et qu'un des facteurs est nul (enfin dans un anneau intègre comme Q R ou C).
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  16. #16
    Membre éclairé
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Points : 773
    Points
    773
    Par défaut
    Ok, merci à vous deux

  17. #17
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    *
    Donc si c'est une somme tu passes 0 en troisième argument.
    Effectivement. Il est logique de passer un troisième argument en fonction de la transformation appliquée sur la liste. Mais c’est parce que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    If the optional initializer is present, it is placed before the items 
    Doc.
    Cela permet de faire d’ailleurs des trucs originaux:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    L = [2,3,5]
    from operator import mul
    print reduce(mul,L,'coucou ')
    coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou coucou





    *
    faire le produit d'une liste vide ne doit-il pas être 0 ?
    Pourquoi diantre y aurait-il une règle universelle ?
    Tout dépend de ce à quoi sert de réduire une liste dans un programme.
    Malgré les considérations savantes dans les messages précédents, j’entends bien pouvoir continuer à faire ce que je veux dans mes programmes





    *
    cause passer une liste de chaines en argument retournerait également 0
    Ah bon ??! Ce n’est pas ce que j’ai constaté en faisant tourner ton code, N.tox.
    D’ailleurs, il y a une erreur: il est écrit def p a,b: au lieu de def p(a,b): dans ton code.





    *
    On peut aussi renvoyer None lorsque le résultat n'a pas de sens, au lieu de déclencher une exception. Cela nécessite un test sur le résultat, mais c'est moins violent qu'une exception.
    Intéressante remarque. Qu’entends-tu par “moins violent“ , tyrtamos ?





    *
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    prod = lambda z : (len(z)==0 and [None] or [reduce(lambda x,y : x*y, z)])[0]
    Joo-o-li , tyrtamos !!
    J’ai mis un sacré moment à comprendre comment ça fonctionne !





    *
    cette manière de calculer les factorielles ne donne aucun avantage de temps d'exécution par rapport à la fonction équivalente
    De quelle autre manière parles tu ? Je pense qu’il s’agit de la méthode itérative. La fonction mul() (cf ci-dessous) devrait donc te satisfaire, question temps d’exécution.





    *
    Je constate que cela donne beaucoup de tracas d’intégrer la prise en compte du cas limite “liste vide“, pour pas grand chose à mon avis.
    La vérification que la liste n’est pas vide me semble pourtant simple sans se casser la tête avec des exceptions, longueur de liste ou longueur de sa représentation
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if L: reduce(mul,L)
    else: ce qu’on veut
    Je veux aussi pouvoir distinguer les vrais cas de liste vide de ceux comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    L = [ 0.025, 32, 10, 0.125]
    from operator import mul
    print reduce(mul,L)
    >>>
    1.0

    –––––––––––––––—————————————


    *
    Maintenant, la question est : peut-on encore "compresser" ce code, pourtant déjà fort succinct ?
    Je me suis posé la même question et j’ai cherché une autre solution que la méthode itérative donnée par N.tox


    Comme les list comprehension n’acceptent pas la présence du signe = , on ne peut pas mettre cette iteration avec *= en list comprehension.
    Et je ne me rappelais plus que reduce() existe.


    Par contre, comme les comprehension de liste acceptent les fonctions append(), remove() etc , j’ai eu l’idée d’utiliser une liste de 1 élément comme une pile dont le dernier élément est le produit successivement multiplié par chaque élément de la liste à réduire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    L = [3,4,0.5,2,7]
    li = [1]
    [ li.append( li[-1]*x ) for x in L ]
    print li.pop()
    >>>
    84
    et pour éviter d’avoir une liste auxiliaire qui grandit jusqu’à l’éventuellement très grande taille de L, utiliser pop()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    L = [3,4,0.5,2,7]
    li = [1]
    [ li.append( li.pop()*x ) for x in L ]
    print li.pop()
    mais cette deuxième solution avec pop() est moins rapide que sans pop(). Le travail supplémentaire pour enlever à chaque fois le dernier élément de la liste n’est pas compensé par le fait que la liste à gérer ne s’allonge pas.







    Quand j’ai vu la solution avec reduce() :

    - j’ai fait ’oh !’

    - j’ai comparé les vitesses : la plus rapide de mes solutions avec liste auxiliaire prend 80% plus de temps que la solution avec reduce() et lambda x*y et même 3 fois plus pour des petites listes traitées

    - mais je n’aime pas les fonctions lambda. Je me suis rappelé qu’il y a des fonctions à deux arguments qui font les mêmes choses que les opérateurs +,-,*,\,+=,-=,*=,\* etc.
    La fonction correspondant à * est mul() du module operator.

    J’ai comparé les vitesses des différentes méthodes
    Résultat : reduce(mul,L) est plus rapide que toutes les autres solutions, plus rapide même que la méthode itérative.



    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    from random import randint
    from operator import mul
    from timeit import Timer
     
    taille_liste = 200
    L = [randint(9807,10200)/10000. for i in xrange(taille_liste)]
    L2 = L[:]
     
     
    def prod(x,y):
        return x*y
     
     
    def calcli3(li):
        liaux = [1]
        [liaux.append( mul(liaux.pop(),x)) for x in L]
        return liaux.pop()
    print 'calcli3       ',calcli3(L),L==L2
     
     
    def calcli2(li):
        liaux = [1]
        [liaux.append(liaux.pop()*x) for x in L]
        return liaux.pop()
    print 'calcli2       ',calcli2(L),L==L2
     
     
    def calcli(li):
        liaux = [1]
        [liaux.append( liaux[-1]*x) for x in L]
        return liaux.pop()
    print 'calcli        ',calcli(L),L==L2
     
     
    def redlambda(li):
        return reduce(lambda x,y:x*y , li)
    print 'reduce lambda ',redlambda(L),L==L2
     
     
    def redtyr(li):
        return (len(li)==0 and [None] or [reduce(lambda x,y : x*y, li)])[0]
    print 'redtyr        ',redtyr(L),L==L2
     
     
    def redprod(li):
        return reduce(prod,li)
    print 'reduce prod   ',redprod(L),L==L2
     
     
    def iterante(li):
        x = 1
        for y in li:
            x*=y
        return x
    print 'iterante      ',iterante(L),L==L2
     
     
    def redmul(li):
        return reduce(mul,li)
    print 'reduce mul    ',redmul(L),L==L2
     
     
     
     
     
     
    def affiter(t):
        if 'e' in repr(min(t)):
            miin1,_,miin2 = repr(min(t)).partition('e')
            miin = miin1[0:5].rjust(5) + ' e' + miin2
        else:
            miin = repr(min(t))[0:9]
     
        if 'e' in repr(sum(t)/len(t)):
            suum1,_,suum2 = repr(sum(t)/len(t)).partition('e')
            suum = suum1[0:5].rjust(5) + ' e' + suum2
        else:
            suum = repr(min(t))[0:9]
        print 'min ',miin.ljust(15),'moy ',suum.ljust(15),\
              '=   moyenne   m     iterative x*=y'
     
     
    def aff(t,m,nom):
        if 'e' in repr(min(t)):
            miin1,_,miin2 = repr(min(t)).partition('e')
            miin = miin1[0:5].rjust(5) + ' e' + miin2
        else:
            miin = repr(min(t))[0:9]
     
        if 'e' in repr(sum(t)/len(t)):
            suum1,_,suum2 = repr(sum(t)/len(t)).partition('e')
            suum = suum1[0:5].rjust(5) + ' e' + suum2
        else:
            suum = repr(min(t))[0:9]
     
        print 'min ',miin.ljust(15),'moy ',suum.ljust(15),\
              '=',str(100*sum(t)/len(t)/m)[0:5],'%  de m     '+nom
     
     
     
    for taille_liste in [3,10,50,100,500,1000,5000,10000,50000]:
     
        print 8*'--------'+' taille de liste =',taille_liste,'-------------------'
        L = [randint(9807,10200)/10000. for i in xrange(taille_liste)]
     
        repet,iterat = 5,50
     
        tcalcli3 = Timer('calcli3(L)','from __main__ import calcli3,L').repeat(repet,iterat)
        tcalcli2 = Timer('calcli2(L)','from __main__ import calcli2,L').repeat(repet,iterat)
        tcalcli = Timer('calcli(L)','from __main__ import calcli,L').repeat(repet,iterat)
        tredlambda = Timer('redlambda(L)','from __main__ import redlambda,L').repeat(repet,iterat)
        tredtyr = Timer('redtyr(L)','from __main__ import redtyr,L').repeat(repet,iterat)
        tredprod = Timer('redprod(L)','from __main__ import redprod,L').repeat(repet,iterat)
        titer = Timer('iterante(L)','from __main__ import iterante,L').repeat(repet,iterat)
        tredmul = Timer('redmul(L)','from __main__ import redmul,L').repeat(repet,iterat)
     
        m = sum(titer)/len(titer)
        aff(tcalcli3,m,'liste aux, pop et mul')
        aff(tcalcli2,m,'liste aux, pop et *')
        aff(tcalcli,m,'liste aux et *')
        aff(tredtyr,m,'reduce tyr')
        aff(tredlambda,m,'reduce lambda')
        aff(tredprod,m,'reduce prod')
        affiter(titer)
        aff(tredmul,m,'reduce mul')


    Petite explication sur la construction de L dans le code ci-dessus:

    on ne peut pas utiliser des listes range(n) ou des listes construites de façon analogue car pour de grandes listes, le produit de leurs éléments risque de diverger au point de faire exploser les capacités de calcul. Je sais bien que Python maîtrise fort bien les très très grands nombres et les très très petits, mais mon but n’était pas de parasiter les tests avec cet aspect.

    Une liste avec des nombres autour de 1 a moins de chances de donner un produit qui diverge soit vers l’infini soit vers 0. Mais pour une liste de 2000 nombres par exemple, il ne suffit pas que les 1000 premiers soient en dessous de 1 et que les 1000 autres au dessus de 1, car les 1000 premiers vont faire “diverger“ avant d’atteindre le 1.

    La solution est d’utiliser une répartition aléatoire autour de 1 dans la liste de nombres traitée.
    D’où mon utilisation de randint(9807,10200)/10000 pour avoir des nombres aléatoires compris entre 0.9807 et 1.020.

    L’équilibre est si délicat qu’il suffit de changer 0.9807 en 0.9806 pour voir le produit final sur une grande liste se décaler vers 0. J’ai gardé un petit déséquilibre en faveur de 1.020 pour orienter le produit au dessus de 1.

    Il n’étonnera personne que 1 / 1.020 = 0.9804 ( 0.9803922)







    En faisant varier la longueur de la liste traitée: les rapports de vitesse entre les différentes méthodes ne changent pas.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    calcli3        1.16061300825 True
    calcli2        1.16061300825 True
    calcli         1.16061300825 True
    reduce lambda  1.16061300825 True
    redtyr         1.16061300825 True
    reduce prod    1.16061300825 True
    iterante       1.16061300825 True
    reduce mul     1.16061300825 True
    ---------------------------------------------------------------- taille de liste = 3 -------------------
    min  0.0012758       moy  0.0012758       = 493.4 %  de m     liste aux, pop et mul
    min  0.0011277       moy  0.0011277       = 469.0 %  de m     liste aux, pop et *
    min  0.0010344       moy  0.0010344       = 413.3 %  de m     liste aux et *
    min  0.0005869       moy  0.0005869       = 226.8 %  de m     reduce tyr
    min  0.0003478       moy  0.0003478       = 134.9 %  de m     reduce lambda
    min  0.0003008       moy  0.0003008       = 113.7 %  de m     reduce prod
    min  0.0002642       moy  0.0002642       =   moyenne   m     iterative x*=y
    min  0.0002128       moy  0.0002128       = 80.66 %  de m     reduce mul
    ---------------------------------------------------------------- taille de liste = 10 -------------------
    min  0.0032006       moy  0.0032006       = 637.5 %  de m     liste aux, pop et mul
    min  0.0026805       moy  0.0026805       = 493.2 %  de m     liste aux, pop et *
    min  0.0021201       moy  0.0021201       = 1428. %  de m     liste aux et *
    min  0.0010643       moy  0.0010643       = 189.2 %  de m     reduce tyr
    min  0.0008313       moy  0.0008313       = 147.5 %  de m     reduce lambda
    min  0.0007841       moy  0.0007841       = 136.6 %  de m     reduce prod
    min  0.0005453       moy  0.0005453       =   moyenne   m     iterative x*=y
    min  0.0004179       moy  0.0004179       = 72.98 %  de m     reduce mul
    ---------------------------------------------------------------- taille de liste = 50 -------------------
    min  0.0136679       moy  0.0136679       = 638.5 %  de m     liste aux, pop et mul
    min  0.0108443       moy  0.0108443       = 505.2 %  de m     liste aux, pop et *
    min  0.0073537       moy  0.0073537       = 359.2 %  de m     liste aux et *
    min  0.0036890       moy  0.0036890       = 179.8 %  de m     reduce tyr
    min  0.0034750       moy  0.0034750       = 171.2 %  de m     reduce lambda
    min  0.0034694       moy  0.0034694       = 164.4 %  de m     reduce prod
    min  0.0020650       moy  0.0020650       =   moyenne   m     iterative x*=y
    min  0.0015214       moy  0.0015214       = 73.79 %  de m     reduce mul
    ---------------------------------------------------------------- taille de liste = 100 -------------------
    min  0.0258552       moy  0.0258552       = 602.4 %  de m     liste aux, pop et mul
    min  0.0210199       moy  0.0210199       = 483.5 %  de m     liste aux, pop et *
    min  0.0131111       moy  0.0131111       = 311.6 %  de m     liste aux et *
    min  0.0069994       moy  0.0069994       = 162.7 %  de m     reduce tyr
    min  0.0067600       moy  0.0067600       = 161.0 %  de m     reduce lambda
    min  0.0067307       moy  0.0067307       = 157.7 %  de m     reduce prod
    min  0.0040471       moy  0.0040471       =   moyenne   m     iterative x*=y
    min  0.0029031       moy  0.0029031       = 70.06 %  de m     reduce mul
    ---------------------------------------------------------------- taille de liste = 500 -------------------
    min  0.1207069       moy  0.1207069       = 575.2 %  de m     liste aux, pop et mul
    min  0.1276198       moy  0.1276198       = 606.9 %  de m     liste aux, pop et *
    min  0.0600827       moy  0.0600827       = 316.1 %  de m     liste aux et *
    min  0.0340546       moy  0.0340546       = 164.5 %  de m     reduce tyr
    min  0.0341127       moy  0.0341127       = 163.6 %  de m     reduce lambda
    min  0.0337665       moy  0.0337665       = 161.3 %  de m     reduce prod
    min  0.0194960       moy  0.0194960       =   moyenne   m     iterative x*=y
    min  0.0142562       moy  0.0142562       = 73.32 %  de m     reduce mul
    ---------------------------------------------------------------- taille de liste = 1000 -------------------
    min  0.2372293       moy  0.2372293       = 592.0 %  de m     liste aux, pop et mul
    min  0.2065625       moy  0.2065625       = 538.2 %  de m     liste aux, pop et *
    min  0.1176015       moy  0.1176015       = 333.0 %  de m     liste aux et *
    min  0.0679474       moy  0.0679474       = 166.3 %  de m     reduce tyr
    min  0.0675650       moy  0.0675650       = 208.8 %  de m     reduce lambda
    min  0.0673244       moy  0.0673244       = 169.1 %  de m     reduce prod
    min  0.0389982       moy  0.0389982       =   moyenne   m     iterative x*=y
    min  0.0283952       moy  0.0283952       = 69.38 %  de m     reduce mul
    ---------------------------------------------------------------- taille de liste = 5000 -------------------
    min  1.2524161       moy  1.2524161       = 680.8 %  de m     liste aux, pop et mul
    min  1.0097850       moy  1.0097850       = 571.6 %  de m     liste aux, pop et *
    min  0.6731243       moy  0.6731243       = 356.1 %  de m     liste aux et *
    min  0.3638051       moy  0.3638051       = 187.1 %  de m     reduce tyr
    min  0.3582860       moy  0.3582860       = 199.8 %  de m     reduce lambda
    min  0.3601561       moy  0.3601561       = 196.1 %  de m     reduce prod
    min  0.1989853       moy  0.1989853       =   moyenne   m     iterative x*=y
    min  0.1457785       moy  0.1457785       = 73.34 %  de m     reduce mul
    ---------------------------------------------------------------- taille de liste = 10000 -------------------
    min  2.4748497       moy  2.4748497       = 567.3 %  de m     liste aux, pop et mul
    min  1.9772130       moy  1.9772130       = 463.6 %  de m     liste aux, pop et *
    min  1.2596735       moy  1.2596735       = 296.1 %  de m     liste aux et *
    min  0.7107601       moy  0.7107601       = 166.7 %  de m     reduce tyr
    min  0.7041515       moy  0.7041515       = 159.6 %  de m     reduce lambda
    min  0.7054217       moy  0.7054217       = 165.8 %  de m     reduce prod
    min  0.4088483       moy  0.4088483       =   moyenne   m     iterative x*=y
    min  0.2939834       moy  0.2939834       = 65.52 %  de m     reduce mul
    ---------------------------------------------------------------- taille de liste = 50000 -------------------
    min  12.883870       moy  12.883870       = 530.2 %  de m     liste aux, pop et mul
    min  10.617487       moy  10.617487       = 437.6 %  de m     liste aux, pop et *
    min  7.4657122       moy  7.4657122       = 303.0 %  de m     liste aux et *
    min  3.9859004       moy  3.9859004       = 161.7 %  de m     reduce tyr
    min  3.9225915       moy  3.9225915       = 163.4 %  de m     reduce lambda
    min  3.9531339       moy  3.9531339       = 164.2 %  de m     reduce prod
    min  2.3004552       moy  2.3004552       =   moyenne   m     iterative x*=y
    min  1.7916288       moy  1.7916288       = 76.24 %  de m     reduce mul
    Je m’attendais à ce que la solution de Tyrtamos soit un peu plus lente que la solution reduce(lambda x*y, L)
    et que la solution reduce(prod, L) soit par contre plus rapide que reduce(lambda, L)
    Il n'en est rien.
    En fait les trois méthodes reduce(lambda x*y, L) , reduce(prod, L) , reduce(lambda tyrtamos, L) apparaissent être grosso modo de même vitesse:
    Elles sont au moins 50% plus longues que la méthode itérative.



    Quant à reduce(mul, L) sa vitesse est 70 à 75 % celle de la méthode itérative.
    Je ne m’y attendais pas. Pour moi, les itérations sont très rapides et *= aussi.
    Je me dis que si mul() est plus rapide, ce doit être dû à la manière dont mul() est écrite en C++ et dont la méthode itérative se trouve écrite aussi.
    En fait, la recherche de concision ne sert pas à grand chose, c’est la traduction en C++ sous-jacente qui importe, je pense. Mes fonctions calcli() , clacli2() et calcli3() sont aussi condensées que la méthode itérative et pourtant elles sont 4 à 6 fois plus lente qu’elle.
    Il est d'ailleurs curieux de voir que la fonction calcli3() dans laquelle mul() remplace * est la plus lente des trois.

  18. #18
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 462
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 462
    Points : 9 249
    Points
    9 249
    Billets dans le blog
    6
    Par défaut
    Bonjour eyquem.

    Citation Envoyé par eyquem Voir le message
    Intéressante remarque. Qu’entends-tu par “moins violent“ , tyrtamos ?
    Je veux seulement dire que la génération d'une exception produit une rupture dans le déroulement du code. Ce n'est pas le cas du renvoi de None. Je n'ai cependant rien contre la gestion des exceptions que j'utilise beaucoup.

    Citation Envoyé par eyquem Voir le message
    Pourquoi diantre y aurait-il une règle universelle ?
    Tout dépend de ce à quoi sert de réduire une liste dans un programme.
    Malgré les considérations savantes dans les messages précédents, j’entends bien pouvoir continuer à faire ce que je veux dans mes programmes
    Je comprends assez bien que 1**0=1 et 0!=1, même si ça n'a guère d'interprétation physique. Je peux en tout cas attester que c'est utile pour le calcul de certaines formules.

    Mais même si j'en comprends bien le fondement théorique, j'ai effectivement du mal à avaler que rien*rien=1. Ça viendra peut-être avec le temps...?

    En tout cas, dans l'application informatique, il faut bien vérifier au coup par coup que ce résultat a un sens.

    Citation Envoyé par eyquem Voir le message
    De quelle autre manière parles tu ? Je pense qu’il s’agit de la méthode itérative.
    Oui! Par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    def prod(L):
        x=1
        for e in L:
            x*=e
        return x
    Citation Envoyé par eyquem Voir le message
    La fonction mul() devrait donc te satisfaire, question temps d’exécution.
    J'ai donc essayé de comparer les durées d'exécution de la fonction itérative ci-dessus avec les 2 définitions suivantes:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    prod2 = lambda z : reduce(lambda x,y:x*y,z,1)
    prod3 = lambda z : reduce(mul,z,1)
    Et curieusement, je ne trouvais pas un grand avantage à utiliser mul() plutôt que lambda (< à env -10%), et j'ai fini par trouver pourquoi: j'utilisais une liste d'entier (random.randint).

    Avec une liste de flottant, je retrouve effectivement un avantage important de mul par rapport à lambda (env. -50%).

    Mais dans tous les cas, la définition de fonction "normale" (itérative) est encore plus rapide qu'avec mul() (env. -5%). Et comme j'attache beaucoup d'importance à la lisibilité du code, je la préfère nettement.

    Tyrtamos
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  19. #19
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut @ tyrtamos
    Salut.

    1/floats/entiers

    Et curieusement, je ne trouvais pas un grand avantage à utiliser mul() plutôt que lambda (< à env -10%), et j'ai fini par trouver pourquoi: j'utilisais une liste d'entier (random.randint).

    Avec une liste de flottant, je retrouve effectivement un avantage important de mul par rapport à lambda (env. -50%).
    Je n’ai pas du tout pensé à ceci. Effectivement, j’aurais pu me demander ce qu’il se passe avec une liste de nombres autres que proches de 1, et avec des entiers uniquement.

    Donc j’ai repris mon code et j’ai changé
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for taille_liste in [3,10,50,100,500,1000,5000,10000,50000]:
            L = [randint(9807,10200)/10000. for i in xrange(taille_liste)]
    en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for taille_liste in [3,6,12,24,40,80,160]:
        L = [randint(1,12) for i in xrange(taille_liste)]


    J’ai aussi répété deux fois les instructions dans la boucle, de façon à faire tourner les fonctions 3 fois sur chaque liste produite par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    L = [randint(1,12) for i in xrange(taille_liste)]
    Je ne savais en effet pas si les variations de temps obervé d’une utilisation à l’autre du programme était une variation dûe à la différence de liste construite, ou à une autre raison.

    Cette variation m’intrigue parce que je croyais que l’utilisation de Timer permettait justement d’éliminer toute variation dans la mesure d’un processus. Je constate souvent qu’il n’en est rien mais là en plus il y a la variation aléatoire de la liste construite.

    Il est sorti une fois une vitesse de reduce mul de 450 % celle de la méthode itérative !! À quoi cela peut il bien être dû ? Mystère.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    from random import randint
    from operator import mul
    from timeit import Timer
     
    taille_liste = 200
    L = [randint(9807,10200)/10000. for i in xrange(taille_liste)]
    L2 = L[:]
     
     
    def prod(x,y):
        return x*y
     
     
    def calcli3(li):
        liaux = [1]
        [liaux.append( mul(liaux.pop(),x)) for x in L]
        return liaux.pop()
    print 'calcli3       ',calcli3(L),L==L2
     
     
    def calcli2(li):
        liaux = [1]
        [liaux.append(liaux.pop()*x) for x in L]
        return liaux.pop()
    print 'calcli2       ',calcli2(L),L==L2
     
     
    def calcli(li):
        liaux = [1]
        [liaux.append( liaux[-1]*x) for x in L]
        return liaux.pop()
    print 'calcli        ',calcli(L),L==L2
     
     
    def redlambda(li):
        return reduce(lambda x,y:x*y , li)
    print 'reduce lambda ',redlambda(L),L==L2
     
     
    def redtyr(li):
        return (len(li)==0 and [None] or [reduce(lambda x,y : x*y, li)])[0]
    print 'redtyr        ',redtyr(L),L==L2
     
     
    def redprod(li):
        return reduce(prod,li)
    print 'reduce prod   ',redprod(L),L==L2
     
     
    def iterante(li):
        x = 1
        for y in li:
            x*=y
        return x
    print 'iterante      ',iterante(L),L==L2
     
     
    def redmul(li):
        return reduce(mul,li)
    print 'reduce mul    ',redmul(L),L==L2
     
     
     
     
     
     
    def affiter(t):
        if 'e' in repr(min(t)):
            miin1,_,miin2 = repr(min(t)).partition('e')
            miin = miin1[0:5].rjust(5) + ' e' + miin2
        else:
            miin = repr(min(t))[0:9]
     
        if 'e' in repr(sum(t)/len(t)):
            suum1,_,suum2 = repr(sum(t)/len(t)).partition('e')
            suum = suum1[0:5].rjust(5) + ' e' + suum2
        else:
            suum = repr(min(t))[0:9]
        print 'min ',miin.ljust(15),'moy ',suum.ljust(15),\
              '=   moyenne   m     iterative x*=y'
     
     
    def aff(t,m,nom):
        if 'e' in repr(min(t)):
            miin1,_,miin2 = repr(min(t)).partition('e')
            miin = miin1[0:5].rjust(5) + ' e' + miin2
        else:
            miin = repr(min(t))[0:9]
     
        if 'e' in repr(sum(t)/len(t)):
            suum1,_,suum2 = repr(sum(t)/len(t)).partition('e')
            suum = suum1[0:5].rjust(5) + ' e' + suum2
        else:
            suum = repr(min(t))[0:9]
     
        print 'min ',miin.ljust(15),'moy ',suum.ljust(15),\
              '=',str(100*sum(t)/len(t)/m)[0:5],'%  de m     '+nom
     
     
     
    for taille_liste in [3,6,12,24,40,80,160]:
     
        print 3*'-----------'+'- ENTIERS '+4*'---------'+' taille de liste =',taille_liste,'---'
        L = [randint(1,12) for i in xrange(taille_liste)]
     
        repet,iterat = 5,50
     
        tcalcli3 = Timer('calcli3(L)','from __main__ import calcli3,L').repeat(repet,iterat)
        tcalcli2 = Timer('calcli2(L)','from __main__ import calcli2,L').repeat(repet,iterat)
        tcalcli = Timer('calcli(L)','from __main__ import calcli,L').repeat(repet,iterat)
        tredlambda = Timer('redlambda(L)','from __main__ import redlambda,L').repeat(repet,iterat)
        tredtyr = Timer('redtyr(L)','from __main__ import redtyr,L').repeat(repet,iterat)
        tredprod = Timer('redprod(L)','from __main__ import redprod,L').repeat(repet,iterat)
        titer = Timer('iterante(L)','from __main__ import iterante,L').repeat(repet,iterat)
        tredmul = Timer('redmul(L)','from __main__ import redmul,L').repeat(repet,iterat)
     
        m = sum(titer)/len(titer)
        aff(tcalcli3,m,'liste aux, pop et mul')
        aff(tcalcli2,m,'liste aux, pop et *')
        aff(tcalcli,m,'liste aux et *')
        aff(tredtyr,m,'reduce tyr')
        aff(tredlambda,m,'reduce lambda')
        aff(tredprod,m,'reduce prod')
        affiter(titer)
        aff(tredmul,m,'reduce mul')
     
        print '==============================='
     
        tcalcli3 = Timer('calcli3(L)','from __main__ import calcli3,L').repeat(repet,iterat)
        tcalcli2 = Timer('calcli2(L)','from __main__ import calcli2,L').repeat(repet,iterat)
        tcalcli = Timer('calcli(L)','from __main__ import calcli,L').repeat(repet,iterat)
        tredlambda = Timer('redlambda(L)','from __main__ import redlambda,L').repeat(repet,iterat)
        tredtyr = Timer('redtyr(L)','from __main__ import redtyr,L').repeat(repet,iterat)
        tredprod = Timer('redprod(L)','from __main__ import redprod,L').repeat(repet,iterat)
        titer = Timer('iterante(L)','from __main__ import iterante,L').repeat(repet,iterat)
        tredmul = Timer('redmul(L)','from __main__ import redmul,L').repeat(repet,iterat)
     
        m = sum(titer)/len(titer)
        aff(tcalcli3,m,'liste aux, pop et mul')
        aff(tcalcli2,m,'liste aux, pop et *')
        aff(tcalcli,m,'liste aux et *')
        aff(tredtyr,m,'reduce tyr')
        aff(tredlambda,m,'reduce lambda')
        aff(tredprod,m,'reduce prod')
        affiter(titer)
        aff(tredmul,m,'reduce mul')
     
        print '========================'
     
        tcalcli3 = Timer('calcli3(L)','from __main__ import calcli3,L').repeat(repet,iterat)
        tcalcli2 = Timer('calcli2(L)','from __main__ import calcli2,L').repeat(repet,iterat)
        tcalcli = Timer('calcli(L)','from __main__ import calcli,L').repeat(repet,iterat)
        tredlambda = Timer('redlambda(L)','from __main__ import redlambda,L').repeat(repet,iterat)
        tredtyr = Timer('redtyr(L)','from __main__ import redtyr,L').repeat(repet,iterat)
        tredprod = Timer('redprod(L)','from __main__ import redprod,L').repeat(repet,iterat)
        titer = Timer('iterante(L)','from __main__ import iterante,L').repeat(repet,iterat)
        tredmul = Timer('redmul(L)','from __main__ import redmul,L').repeat(repet,iterat)
     
        m = sum(titer)/len(titer)
        aff(tcalcli3,m,'liste aux, pop et mul')
        aff(tcalcli2,m,'liste aux, pop et *')
        aff(tcalcli,m,'liste aux et *')
        aff(tredtyr,m,'reduce tyr')
        aff(tredlambda,m,'reduce lambda')
        aff(tredprod,m,'reduce prod')
        affiter(titer)
        aff(tredmul,m,'reduce mul')

    Voici donc ce qui sort avec des listes d’entiers.
    J’ai sélectionné un résultat orthodoxe parmi plusieurs.Dans certains en effet, la variabilité sort un 165% pour redmul() et autres aberrations perturbantes sans signification.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    calcli3        0.830839711062 True
    calcli2        0.830839711062 True
    calcli         0.830839711062 True
    reduce lambda  0.830839711062 True
    redtyr         0.830839711062 True
    reduce prod    0.830839711062 True
    iterante       0.830839711062 True
    reduce mul     0.830839711062 True
    ---------------------------------- ENTIERS ------------------------ taille de liste = 3 ---------
    min  0.0012347       moy  0.0012347       = 483.9 %  de m     liste aux, pop et mul
    min  0.0010847       moy  0.0010847       = 420.1 %  de m     liste aux, pop et *
    min  0.0009978       moy  0.0009978       = 435.4 %  de m     liste aux et *
    min  0.0005925       moy  0.0005925       = 229.2 %  de m     reduce tyr
    min  0.0003584       moy  0.0003584       = 144.4 %  de m     reduce lambda
    min  0.0003235       moy  0.0003235       = 125.5 %  de m     reduce prod
    min  0.0002572       moy  0.0002572       =   moyenne   m     iterative x*=y
    min  0.0002226       moy  0.0002226       = 86.51 %  de m     reduce mul
    ---------------------------------- ENTIERS ------------------------ taille de liste = 6 ---------
    min  0.0020957       moy  0.0020957       = 683.0 %  de m     liste aux, pop et mul
    min  0.0017896       moy  0.0017896       = 463.6 %  de m     liste aux, pop et *
    min  0.0015032       moy  0.0015032       = 392.9 %  de m     liste aux et *
    min  0.0008364       moy  0.0008364       = 213.9 %  de m     reduce tyr
    min  0.0005995       moy  0.0005995       = 153.6 %  de m     reduce lambda
    min  0.0005581       moy  0.0005581       = 142.9 %  de m     reduce prod
    min  0.0003774       moy  0.0003774       =   moyenne   m     iterative x*=y
    min  0.0003212       moy  0.0003212       = 82.36 %  de m     reduce mul
    ---------------------------------- ENTIERS ------------------------ taille de liste = 12 ---------
    min  0.0035540       moy  0.0035540       = 606.4 %  de m     liste aux, pop et mul
    min  0.0030168       moy  0.0030168       = 506.7 %  de m     liste aux, pop et *
    min  0.0023089       moy  0.0023089       = 378.4 %  de m     liste aux et *
    min  0.0012694       moy  0.0012694       = 205.2 %  de m     reduce tyr
    min  0.0010434       moy  0.0010434       = 170.7 %  de m     reduce lambda
    min  0.0010068       moy  0.0010068       = 165.4 %  de m     reduce prod
    min  0.0006193       moy  0.0006193       =   moyenne   m     iterative x*=y
    min  0.0004888       moy  0.0004888       = 91.18 %  de m     reduce mul
    ---------------------------------- ENTIERS ------------------------ taille de liste = 24 ---------
    min  0.0071690       moy  0.0071690       = 484.7 %  de m     liste aux, pop et mul
    min  0.0060502       moy  0.0060502       = 424.8 %  de m     liste aux, pop et *
    min  0.0042798       moy  0.0042798       = 289.7 %  de m     liste aux et *
    min  0.0026838       moy  0.0026838       = 179.6 %  de m     reduce tyr
    min  0.0024265       moy  0.0024265       = 190.1 %  de m     reduce lambda
    min  0.0023659       moy  0.0023659       = 158.5 %  de m     reduce prod
    min  0.0015063       moy  0.0015063       =   moyenne   m     iterative x*=y
    min  0.0012702       moy  0.0012702       = 85.76 %  de m     reduce mul
    ---------------------------------- ENTIERS ------------------------ taille de liste = 40 ---------
    min  0.0124177       moy  0.0124177       = 431.0 %  de m     liste aux, pop et mul
    min  0.0105295       moy  0.0105295       = 358.6 %  de m     liste aux, pop et *
    min  0.0075621       moy  0.0075621       = 266.5 %  de m     liste aux et *
    min  0.0048768       moy  0.0048768       = 162.9 %  de m     reduce tyr
    min  0.0044424       moy  0.0044424       = 147.1 %  de m     reduce lambda
    min  0.0045069       moy  0.0045069       = 149.1 %  de m     reduce prod
    min  0.0029456       moy  0.0029456       =   moyenne   m     iterative x*=y
    min  0.0024947       moy  0.0024947       = 104.7 %  de m     reduce mul
    ---------------------------------- ENTIERS ------------------------ taille de liste = 80 ---------
    min  0.0241340       moy  0.0241340       = 482.6 %  de m     liste aux, pop et mul
    min  0.0202450       moy  0.0202450       = 420.6 %  de m     liste aux, pop et *
    min  0.0141543       moy  0.0141543       = 232.3 %  de m     liste aux et *
    min  0.0094721       moy  0.0094721       = 157.1 %  de m     reduce tyr
    min  0.0091017       moy  0.0091017       = 144.4 %  de m     reduce lambda
    min  0.0091897       moy  0.0091897       = 149.5 %  de m     reduce prod
    min  0.0063876       moy  0.0063876       =   moyenne   m     iterative x*=y
    min  0.0051945       moy  0.0051945       = 89.73 %  de m     reduce mul
    ---------------------------------- ENTIERS ------------------------ taille de liste = 160 ---------
    min  0.0508475       moy  0.0508475       = 350.4 %  de m     liste aux, pop et mul
    min  0.0418477       moy  0.0418477       = 290.6 %  de m     liste aux, pop et *
    min  0.0283644       moy  0.0283644       = 202.6 %  de m     liste aux et *
    min  0.0197301       moy  0.0197301       = 139.8 %  de m     reduce tyr
    min  0.0197533       moy  0.0197533       = 134.4 %  de m     reduce lambda
    min  0.0198667       moy  0.0198667       = 139.9 %  de m     reduce prod
    min  0.0141741       moy  0.0141741       =   moyenne   m     iterative x*=y
    min  0.0117710       moy  0.0117710       = 104.0 %  de m     reduce mul




    Ces résultats ne sont pas foncièrement différents de ceux avec des listes de réels:

    - la fonction reduce(mul,L) reste plus rapide que la méthode itérative

    Peut être un peu moins rapide: 80 à 85 % de la méthode itérative au lieu de 70-75 %.

    - comme tu le dis, reduce(mul,L) par rapport à reduce(lambda x * y,L) est plus rapide, je dirais de 40% plutôt que 50%, c’est à dire que sa vitesse est plutôt 60% de celle de reduce(lambda x * y,L)

    Mais donc pour moi, pas de différence entre liste d’entiers et liste de floats.












    2/ lambda

    Ensuite je me suis dit que les observations dont tu fais état étaient certainement dûs au fait que tu rajoutes une fonction lambda dans les définitions de fonctions.
    Par exemple de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    reduce(lambda x,y: x*y , li)
    tu en fais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (lambda z : reduce(lambda x,y: x*y,z,1))(li)
    Ce n’est plus un fonction reduce() à deux arguments ( une fonction lambda et li),
    c’est une fonction à un seul argument (la fonction reduce)
    Ça ne me paraissait pas la meilleure chose à faire que d’introduire une lambda supplémentaire.
    En effet, d’après les résultats que j’ai obtenus, si reduce(mul,L) est plus rapide que reduce(lambda x*y,L) ou reduce(prod,L) par rapport à l’itérative, c’est bien à cause d’une fonction lambda ou prod moins efficace que mul et non pas à cause de l’utilisation de reduce() qui n’est évidemment pas dans l’itérative.



    Donc j’ai testé avec le code suivant pour comparer
    redlambda() et prod2_lamb_redlambda()
    redmul() et prod3_lamb_redmul()


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    from random import randint
    from operator import mul
    from timeit import Timer
     
    taille_liste = 200
    L = [randint(9807,10200)/10000. for i in xrange(taille_liste)]
    L2 = L[:]
     
     
    def prod(x,y):
        return x*y
     
     
     
     
     
    def redlambda(li):
        return reduce(lambda x,y:x*y , li)
    print 'reduce lambda ',redlambda(L),L==L2
     
    def prod2_lamb_redlambda(li):
        return (lambda z : reduce(lambda x,y:x*y,z,1))(li)
    print 'prod2_lamb_redlambda ',prod2_lamb_redlambda(L),L==L2
     
     
     
    def redprod(li):
        return reduce(prod,li)
    print 'reduce prod   ',redprod(L),L==L2
     
     
    def iterante(li):
        x = 1
        for y in li:
            x*=y
        return x
    print 'iterante      ',iterante(L),L==L2
     
     
    def redmul(li):
        return reduce(mul,li)
    print 'reduce mul    ',redmul(L),L==L2
     
    def prod3_lamb_redmul(li):
        return (lambda z : reduce(mul,z,1))(li)
    print 'prod3_lamb_redmul ',prod3_lamb_redmul(L),L==L2
     
     
     
     
     
     
     
    def affiter(t):
        if 'e' in repr(min(t)):
            miin1,_,miin2 = repr(min(t)).partition('e')
            miin = miin1[0:5].rjust(5) + ' e' + miin2
        else:
            miin = repr(min(t))[0:9]
     
        if 'e' in repr(sum(t)/len(t)):
            suum1,_,suum2 = repr(sum(t)/len(t)).partition('e')
            suum = suum1[0:5].rjust(5) + ' e' + suum2
        else:
            suum = repr(min(t))[0:9]
        print 'min ',miin.ljust(15),'moy ',suum.ljust(15),\
              '=   moyenne   m     iterative x*=y'
     
     
    def aff(t,m,nom):
        if 'e' in repr(min(t)):
            miin1,_,miin2 = repr(min(t)).partition('e')
            miin = miin1[0:5].rjust(5) + ' e' + miin2
        else:
            miin = repr(min(t))[0:9]
     
        if 'e' in repr(sum(t)/len(t)):
            suum1,_,suum2 = repr(sum(t)/len(t)).partition('e')
            suum = suum1[0:5].rjust(5) + ' e' + suum2
        else:
            suum = repr(min(t))[0:9]
     
        print 'min ',miin.ljust(15),'moy ',suum.ljust(15),\
              '=',str(100*sum(t)/len(t)/m)[0:5],'%  de m     '+nom
     
     
     
    for taille_liste in [3,10,50,100,500,1000,5000,10000,50000]:
     
        print 3*'-----------'+'- FLOATS  '+4*'---------'+' taille de liste =',taille_liste,'---'
        L = [randint(9807,10200)/10000. for i in xrange(taille_liste)]
     
        repet,iterat = 5,50
     
        tredlambda = Timer('redlambda(L)','from __main__ import redlambda,L').repeat(repet,iterat)
        tprod2_lamb_redlambda = Timer('prod2_lamb_redlambda(L)','from __main__ import prod2_lamb_redlambda,L').repeat(repet,iterat)
        tredprod = Timer('redprod(L)','from __main__ import redprod,L').repeat(repet,iterat)
        titer = Timer('iterante(L)','from __main__ import iterante,L').repeat(repet,iterat)
        tredmul = Timer('redmul(L)','from __main__ import redmul,L').repeat(repet,iterat)
        tprod3_lamb_redmul = Timer('prod3_lamb_redmul(L)','from __main__ import prod3_lamb_redmul,L').repeat(repet,iterat)
     
     
        m = sum(titer)/len(titer)
     
        aff(tredlambda,m,'reduce lambda')
        aff(tprod2_lamb_redlambda,m,'prod2_lamb_redlambda')
        aff(tredprod,m,'reduce prod')
        affiter(titer)
        aff(tredmul,m,'redmul')
        aff(tprod3_lamb_redmul,m,'prod3_lamb_redmul')

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    reduce lambda  1.20177792959 True
    prod2_lamb_redlambda  1.20177792959 True
    reduce prod    1.20177792959 True
    iterante       1.20177792959 True
    reduce mul     1.20177792959 True
    prod3_lamb_redmul  1.20177792959 True
    ---------------------------------- FLOATS  ------------------------------------ taille de liste = 3 ---
    min  0.0003614       moy  0.0003614       = 137.8 %  de m     reduce lambda
    min  0.0005925       moy  0.0005925       = 230.1 %  de m     prod2_lamb_redlambda
    min  0.0003081       moy  0.0003081       = 116.5 %  de m     reduce prod
    min  0.0002651       moy  0.0002651       =   moyenne   m     iterative x*=y
    min  0.0002209       moy  0.0002209       = 83.39 %  de m     redmul
    min  0.0004134       moy  0.0004134       = 156.2 %  de m     prod3_lamb_redmul
    ---------------------------------- FLOATS  ------------------------------------ taille de liste = 10 ---
    min  0.0008459       moy  0.0008459       = 158.7 %  de m     reduce lambda
    min  0.0010688       moy  0.0010688       = 197.3 %  de m     prod2_lamb_redlambda
    min  0.0007900       moy  0.0007900       = 147.2 %  de m     reduce prod
    min  0.0005411       moy  0.0005411       =   moyenne   m     iterative x*=y
    min  0.0004207       moy  0.0004207       = 79.14 %  de m     redmul
    min  0.0006076       moy  0.0006076       = 112.6 %  de m     prod3_lamb_redmul
    ---------------------------------- FLOATS  ------------------------------------ taille de liste = 50 ---
    min  0.0034630       moy  0.0034630       = 167.1 %  de m     reduce lambda
    min  0.0037063       moy  0.0037063       = 187.3 %  de m     prod2_lamb_redlambda
    min  0.0034079       moy  0.0034079       = 163.5 %  de m     reduce prod
    min  0.0020639       moy  0.0020639       =   moyenne   m     iterative x*=y
    min  0.0015222       moy  0.0015222       = 74.21 %  de m     redmul
    min  0.0016574       moy  0.0016574       = 82.71 %  de m     prod3_lamb_redmul
    ---------------------------------- FLOATS  ------------------------------------ taille de liste = 100 ---
    min  0.0068025       moy  0.0068025       = 170.8 %  de m     reduce lambda
    min  0.0070089       moy  0.0070089       = 178.3 %  de m     prod2_lamb_redlambda
    min  0.0067665       moy  0.0067665       = 170.1 %  de m     reduce prod
    min  0.0039736       moy  0.0039736       =   moyenne   m     iterative x*=y
    min  0.0029073       moy  0.0029073       = 75.63 %  de m     redmul
    min  0.0029967       moy  0.0029967       = 81.75 %  de m     prod3_lamb_redmul
    ---------------------------------- FLOATS  ------------------------------------ taille de liste = 500 ---
    min  0.0341336       moy  0.0341336       = 174.9 %  de m     reduce lambda
    min  0.0343484       moy  0.0343484       = 175.8 %  de m     prod2_lamb_redlambda
    min  0.0341873       moy  0.0341873       = 174.2 %  de m     reduce prod
    min  0.0195186       moy  0.0195186       =   moyenne   m     iterative x*=y
    min  0.0140484       moy  0.0140484       = 71.81 %  de m     redmul
    min  0.0139073       moy  0.0139073       = 71.32 %  de m     prod3_lamb_redmul
    ---------------------------------- FLOATS  ------------------------------------ taille de liste = 1000 ---
    min  0.0683081       moy  0.0683081       = 177.0 %  de m     reduce lambda
    min  0.0675200       moy  0.0675200       = 175.2 %  de m     prod2_lamb_redlambda
    min  0.0682078       moy  0.0682078       = 174.6 %  de m     reduce prod
    min  0.0383559       moy  0.0383559       =   moyenne   m     iterative x*=y
    min  0.0279636       moy  0.0279636       = 72.29 %  de m     redmul
    min  0.0272232       moy  0.0272232       = 71.30 %  de m     prod3_lamb_redmul
    ---------------------------------- FLOATS  ------------------------------------ taille de liste = 5000 ---
    min  0.3437017       moy  0.3437017       = 151.6 %  de m     reduce lambda
    min  0.3441565       moy  0.3441565       = 159.8 %  de m     prod2_lamb_redlambda
    min  0.3410760       moy  0.3410760       = 144.1 %  de m     reduce prod
    min  0.2034942       moy  0.2034942       =   moyenne   m     iterative x*=y
    min  0.1434453       moy  0.1434453       = 60.62 %  de m     redmul
    min  0.1384089       moy  0.1384089       = 58.43 %  de m     prod3_lamb_redmul
    ---------------------------------- FLOATS  ------------------------------------ taille de liste = 10000 ---
    min  0.7166916       moy  0.7166916       = 164.8 %  de m     reduce lambda
    min  0.7145614       moy  0.7145614       = 163.8 %  de m     prod2_lamb_redlambda
    min  0.7174900       moy  0.7174900       = 165.9 %  de m     reduce prod
    min  0.4217337       moy  0.4217337       =   moyenne   m     iterative x*=y
    min  0.3133099       moy  0.3133099       = 68.65 %  de m     redmul
    min  0.2999870       moy  0.2999870       = 74.98 %  de m     prod3_lamb_redmul
    ---------------------------------- FLOATS  ------------------------------------ taille de liste = 50000 ---
    min  3.8819023       moy  3.8819023       = 169.3 %  de m     reduce lambda
    min  3.9543159       moy  3.9543159       = 170.8 %  de m     prod2_lamb_redlambda
    min  3.9234771       moy  3.9234771       = 168.7 %  de m     reduce prod
    min  2.2124448       moy  2.2124448       =   moyenne   m     iterative x*=y
    min  1.6915898       moy  1.6915898       = 76.70 %  de m     redmul
    min  1.6277244       moy  1.6277244       = 73.82 %  de m     prod3_lamb_redmul
    Grosse surprise: que ce soit avec des listes d’entiers ou avec des listes de floats, tes fonctions prod2 et prod3 ne sont pas plus lentes que redlambda() et redmul().

    Tout au plus semblent elles un tout petit peu plus longues, mais ce n’est vraiment pas patent avec cette satanée variabilité des résultats.
    Elles sont plus longues pour des tres petites listes

    Vraiment difficile de retirer des conclusions réutilisables d’un cas de figure à un autre. Je croyais que les lambda introduisaient de la lenteur. Il semble que ce ne soit pas tout à fait ça.










    3/


    Finalement, ce que tu as écrit ne me permet pas de changer de conclusion: l'emploi de reduce(mul,L)() est plus simple et plus rapide que reduce(lambda x,y : x*y , L), reduce(prod, L) et la méthode itérative.
    Mais ça me pose question:

    - je ne trouvais pas un grand avantage à utiliser mul() plutôt que lambda (< à env -10%),
    Je n’ai pas constaté ce faible pourcentage.
    Comment as-tu fait pour l’observer ? Est-ce avec le code dans mon précédent message ?

    - j'ai fini par trouver pourquoi: j'utilisais une liste d'entier (random.randint).
    Avec une liste de flottant, je retrouve effectivement un avantage important de mul par rapport à lambda (env. -50%).

    Non reproductible avec le code ci-dessus.
    Quel est le procédé qui te donne ce résultat ?

    - Mais dans tous les cas, la définition de fonction "normale" (itérative) est encore plus rapide qu'avec mul() (env. -5%).
    Comment as-tu fait pour observer ceci ?
    Je comprends d’autant moins que tu écris “dans tous les cas“ et juste avant “Avec une liste de flottant, je retrouve effectivement un avantage important de mul par rapport à lambda “

    Est-ce que tu pourrais donner un code et des sorties de résultats , stp.
    Pour le moment j’en reste sur mes observations.

    Les performances de l’ordinateur jouent-elles sur les résultats ?
    J’ai un antique ordinateur qui a une fréquence très poussive. Je n’ose même pas dire combien.
    En valeur absolue il est certain que mes programmes tournent moins vite, mais pour des comparaisons sur la base de valeurs relatives, je ne vois pas pourquoi il y aurait une différence.



    4/

    j'attache beaucoup d'importance à la lisibilité du code, je la préfère nettement.
    Je pense que c'est effectivement plus intelligent que de chercher la concision comme j'avais trop tendance à le faire.

    Je n’aime guère les fonctions lambda pour cette raison: lisibilité médiocre

    Pourtant reduce(mul,L) me semble parfaitement clair. Je sais bien, il y a deux arguments, ça n’a pas le caractère épuré d’une fonction multiplie_tout(L). Mais enfin il ne faut pas exagérer. Pour moi lisibilité veut dire “écriture qui ne s’oppose pas à la perception de la signification d'une instruction et de l’enchaînement logique des instuctions“. De ce point de vue, reduce(mul,L) me satisfait presque pleinement.

    Je me demande juste pourquoi, pour en revenir à la question initiale, il existe une fonction sum() et pas une fonction multiplie_tout() dans Python.
    C'est peut être parce qu’on peut additionner des nombres, des listes, des tuples, des fonctions (?) etc tandis qu’on ne peut pas multiplier des listes entre elles etc.

    -

  20. #20
    Membre émérite
    Avatar de SpiceGuid
    Homme Profil pro
    Inscrit en
    Juin 2007
    Messages
    1 704
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 704
    Points : 2 990
    Points
    2 990
    Par défaut
    faire le produit d'une liste vide ne doit-il pas être 0 ?
    La multiplication et son élément neutre 1 forment un monoide sur les entiers.
    La concaténation de liste et son élément neutre (la liste vide) forment un monoide sur les listes.
    Il est souhaitable que la fonction reduce préserve une certaine structure, dans le cas des opérations arithmétiques on veut préserver la structure de monoide.

    On peut vouloir préserver plus que la structure de monoide, par exemple cette fonction de concaténation préserve toute la structure de liste :

    Code Objective-Caml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    # let append l1 l2 =
      List.fold_right (fun a l -> a::l) l1 l2;;
    val append : 'a list -> 'a list -> 'a list = <fun>
    # append [1;2] [3;4];;
    - : int list = [1; 2; 3; 4]
    

    Sur cet exemple (désolé je ne sais pas le coder en Python) on peut voir que l'argument pour reduce n'est pas forcément un élément neutre car l'opération (ici cons) n'admet pas forcément un élément neutre.
    On peut voir aussi que pour une même opération il peut y avoir le choix de l'argument, par exemple ici on pourrait passer la liste vide en argument, on obtiendrait la copie de liste au lieu de la concaténation de liste.

    Par contre pour une opération arithmétique le seul moyen de préserver la structure de monoide c'est l'élément neutre de cette opération.
    Du même auteur: mon projet, le dernier article publié, le blog dvp et le jeu vidéo.
    Avant de poser une question je lis les règles du forum.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 3
    Dernier message: 20/10/2014, 12h34
  2. Opérations arithmétiques sur les caractères
    Par JolyLoic dans le forum C
    Réponses: 6
    Dernier message: 18/01/2009, 21h59
  3. Tri sur les listes
    Par frizou11 dans le forum Général Python
    Réponses: 4
    Dernier message: 14/05/2006, 11h33
  4. Recherche fonction sur les listes
    Par becks dans le forum Général Python
    Réponses: 5
    Dernier message: 05/05/2006, 16h11
  5. Précisions sur les listes
    Par Virgile59 dans le forum Access
    Réponses: 1
    Dernier message: 07/02/2006, 21h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo