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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    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 émérite
    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
    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 confirmé
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    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 confirmé
    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 : 44
    Localisation : France, Saône et Loire (Bourgogne)

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

    Informations forums :
    Inscription : Août 2002
    Messages : 1 864
    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 confirmé
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    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 : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    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 Expert
    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
    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.

  8. #8
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    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 486
    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

  9. #9
    Membre Expert
    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
    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.

    -

  10. #10
    Membre Expert
    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
    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.

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

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    SpiceGuid:
    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.
    Mezigues:
    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
    C'est bien le message que j'ai essayé de faire passer auparavant avec un formalisme (peut-être) plus soft. Mais SpiceGuid va au fond des choses, les listes avec la concaténation forment un monoïde (loi associative, avec neutre [], mais pas de réciproques sauf pour le neutre).
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  12. #12
    Membre Expert
    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
    Par défaut
    Tout cela est de la belle mathématique, mais que pensez vous de reduce(mul,L) et autres solutions comme réponses à la recherche de yoshik ?

  13. #13
    Membre Expert
    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
    Par défaut
    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
    En effet, l'argument intuitif utilisé c'est que:
    • le produit d'une concaténation doit être le produit des listes concaténées, par exemple le produit de append [1;2] [3;4] est 2 × 12
    • toute liste est aussi sa concaténation avec la liste vide, par exemple [1;2;3;4] c'est aussi append [] [1;2;3;4]
    • si le produit de la liste vide est 0 alors le produit de append [] [1;2;3;4] est 0 × 24 = 0
    • si le produit de la liste vide est 1 alors le produit de append [] [1;2;3;4] est 1 × 24 = 24
    • comme append [] [1;2;3;4] est égal à [1;2;3;4] on sait que son produit doit être égal à 24


    (c'est le même argument que celui fourni par Zavonen, mais plus développé et sans le formalisme hard de mon message précédent)

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

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Tout cela est de la belle mathématique, mais que pensez vous de reduce(mul,L) et autres solutions comme réponses à la recherche de yoshik ?
    Et bien, Eyquem, tu as pensé pour nous.
    Après tes posts je ne vois pas bien ce qu'on pourrait ajouter.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  15. #15
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    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 486
    Billets dans le blog
    6
    Par défaut
    Pour eyquem:

    Voilà mon code d'essai:

    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
     
    from operator import mul
    import time
    import random
     
    def prod1(L):
        x=1
        for e in L:
            x*=e
        return x
     
    prod2 = lambda z : reduce(lambda x,y:x*y,z,1)
     
    prod3 = lambda z : reduce(mul,z,1)
     
     
     
    L = [random.random() for i in xrange(1,10001)]
     
    t = time.clock()
    a = prod1(L)
    ta = time.clock()-t
     
    t = time.clock()
    b = prod2(L)
    tb = time.clock()-t
     
    t = time.clock()
    c = prod3(L)
    tc = time.clock()-t
     
    print tc/tb, tc/ta
    Ce qui affiche quelque chose comme:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    0.43192224206 1.06641384758
    Le 1er nombre indique que la solution "mul" est meilleure (ici d'env. -57%) que la solution lambda.

    Le 2ème nombre indique que la solution "mul" est moins bonne (ici de 6%) que la solution itérative. En fait de 1 à 10%.

    Pour avoir des chiffres plus stables, il faudrait recommencer 1000 fois et faire la moyenne.


    Par contre, j'ai voulu une solution comparable à sum(L) en tant que structure d'appel. l'appel prod(L) convient, mais pas reduce(mul,L,1). D'où mon lambda supplémentaire.


    Avec une liste d'entiers obtenus de la même façon:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    L = [random.randint(1000,9999) for i in xrange(1,10001)]
    Le même code produit des résultats très différents:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    0.990703574104 1.0045047644
    Il n'y a alors pratiquement plus de différence entre les 3 méthodes. D'où mon choix du code le plus lisible "dans tous les cas".

    Tyrtamos

  16. #16
    Membre Expert
    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
    Par défaut @ Zavonen et SpiceGuid
    Je ne suis pas d’accord avec vous.

    Je conteste la validité de votre raisonnement se fondant implicitement(Zavonen) ou explicitement (SpiceGuid) sur la notion de monoïde.




    Comme les maths sont loin pour moi, j’ai regardé la définition de monoïde sur Wikipedia. Rien de compliqué:

    un ensemble E muni d’un opérateur binaire OP est un monoïde (E,OP,e) s’il vérifie trois conditions:
    - l’opérateur est interne: x OP y appartient à E
    - l’opérateur est associatif: x OP (y OP Z) = (x OP y) OP z
    - il existe un élément neutre tel que x OP e = x et e OP x = x


    (je n’écris pas e OP x = x OP e car en toute rigueur ce n’est vrai que si l’opérateur est commutatif. Donc e OP x est égal a x OP e parce que les deux sont égaux à x , mais pas pour raison intrinsèque à l’opérateur)



    Quand l’opérateur est défini partout dans E, c’est à dire que l’opération x OP y a un sens quels que soient les éléments x et y choisis, l’opérateur est appelé loi de composition interne.
    La divison est un opérateur binaire interne mais pas une loi de composition interne parce qu’on ne peut pas diviser par 0.

    Quand par dessus le marché tout élément de E a un inverse par rapport à cette loi, E connait une promotion : il est qualifié de Groupe.







    Bon, pour en venir au raisonnement:

    - la multiplication * forme bien un monoïde sur les entiers.
    J’ajoute: sur les réels aussi.

    - on vérifie que la concaténation de liste forme aussi un monoïde sur les listes Python:
    — L1 + L2 est bien une liste : la concaténation est un opérateur interne
    — L1+(L2+L3) = L1+(L2+L3) : la concaténation est associative
    — [ ] est l’élément neutre de la concaténation

    On peut même dire que la concaténation est une loi de composition interne sur les listes.

    Jusqu’ici, c’est OK.

    Mais pourquoi parler de monoïde ?
    Les listes n’ayant pas d’inverses, on ne peut pas parler de Groupe pour l’ensemble des listes Python. Le monoïde est la seule nature algébrique qui reste pour qualifier les listes Python, avec un nombre de conditions minimal, dont l’une concerne l’existence d’un élément neutre, la liste vide [ ] qui pose justement problème pour savoir quelle valeur doit sortir reduce(mul,[ ]).

    Je suis encore d’accord sur ces constats.

    Mais là où je ne le suis plus, c’est qu’à mon avis, faire valoir que, les listes avec la concaténation, et les nombres équipés de la multiplication * , ont la même nature de monoïde, c’est parce que la notion de monoïde est la seule notion mathématique sur laquelle prétendre prendre appui pour résoudre le problème logiquement et parce qu’il y a la conviction plus ou moins consciente qu’on va pouvoir trouver dans les mathématiques le moyen de répondre à la question “faire le produit d'une liste vide ne doit-il pas être 0 ? “ . Moi je me dis: qu’est ce que les mathématiques ont à voir là dedans ?

    Donc on commence par avancer subrepticement une idée qui a toute l’apparence d’un bon principe, mais sans justification:
    -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.
    Pourquoi est-ce souhaitable ?

    Et au fait qu’est ce que ça veut dire
    “PRÉSERVER la structure de monoïde“
    puisque de toutes façons l'ensemble des nombres et l'ensemble des listes sont déjà des monoides indépendamment de l’intervention de reduce() ???

    En réalité, sous l’idée qu’il y a une réponse objective trouvable rationnellement, il y une volonté subjective de trouver une réponse, comme si on ne supportait pas que la question soit sans réponse.

    Concrètement
    “PRÉSERVER la structure de monoïde“
    se traduit par :
    «le produit d'une concaténation DOIT être le produit des listes concaténées»
    : on est passé d’une suggestion à un postulat non justifié, sinon par le but.

    Mais cet énoncé n’a pas beaucoup de sens:
    - il est déjà vrai pour des listes non vides. Ce n’est pas la valeur du produit d’une liste vide qui va y changer quelque chose.
    - cet énoncé n’a aucune utilité pratique pour un programme compilé.
    Un programme ne cherche pas à faire reduce(mul,L1) * reduce(mul,L2) quand il rencontre reduce(mul, L1+L2).
    Ce que je veux dire, c’est qu’un programme ne fait pas de maths, il fait tourner le CPU, l’énoncé
    «le produit d'une concaténation DOIT être le produit des listes concaténées»
    l’indiffère, il n’a de sens qu’intellectuel et il est vrai sans avoir eu à se préoccuper de monoïde.

    Cet énoncé est pour moi une fausse justification. Je me contente fort bien de l’idée que la valeur de reduce(mul,[ ]) est celle que voudra bien lui donner l’auteur d’un code relativement au type de problème qui l’occupera.
    La question est aussi à mon avis une fausse question.






    Je trouve aussi l’expression Op(L1)OpOp(L2) = Op(L1+ L2) de Zavonen bien contestable.


    Si on prend M(L) = multiplication de tous les éléments de la liste L, alors on est obligé d’écrire

    M(L1)*M(L2) = M(L1+L2) et non pas M(L1)MM(L2) = M(L1+L2)
    Ce qui veut dire que la fonction M qui prend UNE liste en argument n’est pas la même chose que l’opérateur * qui multiplie DEUX arguments.

    Donc il y a écriture abusive dans la formule.



    D’autre part, ce n’est pas “ si la loi est associative’ qu’il faudrait écrire mais “si les lois sont associatives“. Car cette formule n’a rien d’une expression de l’associativité.



    Dans
    Il faut bien que Op(L1)OpOp(L2) donne Op(L1+L2) si la loi est associative
    , je vois à nouveau une façon de présenter comme une justification mathématique ce qui n’est qu’un fait constaté, parce qu’il faut bien trouver quelque chose pour arriver à sortir une réponse précise.


    Enfin bon, tout ceci n'est pas bien grave mais mon sens de la rigueur était un peu chiffoné

+ Répondre à la discussion
Cette discussion est résolue.

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