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 :

comparer les lignes d'un fichier


Sujet :

Python

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 15
    Points : 12
    Points
    12
    Par défaut comparer les lignes d'un fichier
    Salut,
    J'essaye douleureusement de faire des trucs simples mais je ne suis pas compatible avec Python on dirait.
    Par exemple je veux afficher seulement les lignes qui finissent par / donc j'essaye ca :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    f=open(sys.argv[1], 'r')
     
    for line in f:
        if line.endswith('/'):
            print line,
     
    f.close()
    Mais ca ne fonctionne pas, une idée du pourquoi ?
    Mon but est de pouvoir a terme implémenter l'algo suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    #   if line endswith "/" append line to dirstring
    #   else
    #     if (dirstring not empty)
    #           printf SetOutPath "$INSTDIR" . join(dirstring)
    #           dirstring=""
    #    else
    #           printf "File \"C:\GNUstep-devel\1.0.11\" line
    le but etant de générer une liste de fichiers compatible avec l'installeur opensource nsis qui a chaque fois qu'il y a un repertoire ajoute la chaine SetOutPath"$INSTDIR suivi du nom du repertoire s'il y en a un:

    SetOutPath "$INSTDIR\bin"
    File "C:\GNUstep-devel\1.0.11\bin\awk"
    ...
    SetOutPath "$INSTDIR\doc\msys"
    File "C:\GNUstep-devel\1.0.11\doc\msys\COPYING"
    ...
    SetOutPath "$INSTDIR\etc"
    File "C:\GNUstep-devel\1.0.11\etc\fstab.sample"
    ...
    SetOutPath "$INSTDIR"
    File "C:\GNUstep-devel\1.0.11\m.ico"
    ...

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 333
    Points : 36 853
    Points
    36 853
    Par défaut os.sep est un caractère pas une fonction
    Salut,

    A la base for line in f équivaut à lire f via realine.
    line contiendra toujours la fin de ligne (\n) et endswith('/') retournera False.

    Exemple de code un peu bourrin (qui marche):

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    import sys, os
    with open(sys.argv[1]) as f:
        for line in f.read().splitlines():
            if line.endswith(os.sep):
                print '%s: is path' % line
            else: print 'line: ', line

    - W
    PS: Ah oui... os.sep = '/' sous Unix, '\' sous Windows.

  3. #3
    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
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    f=open(sys.argv[1], 'r')
     
    for line in f:
        if line.rstrip().endswith('/'):
            print line,
     
    f.close()
    Marche aussi, de façon moins agressive pour la mémoire

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 333
    Points : 36 853
    Points
    36 853
    Par défaut
    Ben oui, c'est du code bourrin....
    - W

  5. #5
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Ben oui, c'est du code bourrin....
    - W
    Du code bourrin de wiztricks ?!

    Moi je marque la page

    Pardon ? A oui ->[]

  6. #6
    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
    un perd tous, tous bourrins


    J’ai comparé plusieurs façons de faire le test sur un fichier des 250000 octets et 23469 lignes.

    En stockant y = os.sep en mémoire vive au lieu de le calculer à chaque tour,
    et en testant par if ln[-2:-1]==os.sep au lieu de faire if ln.endswith(os.sep) , on diminue le temps d’exécution de 12 %.



    Sur la base des temps minimaux trouvés lors de 1000 essais avec le code suivant, j’ai trouvé la hiérarchie de temps d’exécution suivante:

    if ln.endswith(os.sep)
    114,1


    if ln[-2:-1]==os.sep
    112,2


    y = os.sep
    if ln.endswith(y)
    103,5


    y = os.sep
    if ln[-2:-1]==y
    100



    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
    from time import clock
    import os
     
    iterations = 10
     
    A,B,C,D = [],[],[],[]
    for i in xrange(iterations):
        if i%10==0:
            print i,
     
        f = open('abcd.txt')
        li = []
        te = clock()
        for ln in f:
            if ln.endswith(os.sep):
                li.append(repr(ln))
        tf = clock()
        A.append(tf-te)
        f.close()
     
        f = open('abcd.txt')
        li = []
        te =clock()
        for ln in f:
            if ln[-2:-1]==os.sep:
                li.append(repr(ln))
        tf = clock()
        B.append(tf-te)
        f.close()
     
        f = open('abcd.txt')
        li = []
        y = os.sep
        te = clock()
        for ln in f:
            if ln.endswith(y):
                li.append(repr(ln))
        tf = clock()
        C.append(tf-te)
        f.close()
     
        f = open('abcd.txt')
        li = []
        y = os.sep
        te =clock()
        for ln in f:
            if ln[-2:-1]==y:
                li.append(repr(ln))
        tf = clock()
        D.append(tf-te)
        f.close()
     
    print
    print min(A)
    print min(B)
    print min(C)
    print min(D)
    f = open('abcd.txt')
    i=0
    for ln in f:
        i+=1
    f.close()
    print i

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 333
    Points : 36 853
    Points
    36 853
    Par défaut
    En stockant y = os.sep en mémoire vive au lieu de le calculer à chaque tour, et en testant par if ln[-2:-1]==os.sep au lieu de faire if ln.endswith(os.sep) , on diminue le temps d’exécution de 12 %.
    os.sep est aussi en mémoire vive.
    y = os.sep met os.sep dans la variable locale y.

    Python étant interprété, endswith(y) n'a plus besoin de parcourir l'arborescence pour arriver à trouver ce qu'est la valeur correspondante.
    Note la résolution de os.sep passe par trouver os dans le dictionnaire global puis l'attribut sep puis le contenu de... et le comparer à.

    ln[-2:-1] comparé à ln.endswith(machin) c'est différent.
    cas ln[-2:-1]: on dit l'avant dernier caractère à comparer avec...
    cas ln.endswith: nous sommes dans un cas plus général ou il faut déjà récupérer la longueur de ce qu'on veut comparer,...

    Après la question est est-ce qu'on veut développer du code rapidement et rester a peu près lisible ou est-ce qu'on veut développer un code le plus efficace possible, et dans ce cas ne serait-il pas préférable d'utiliser un langage tel que C ou C++ plutôt que Python?

    - W

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 333
    Points : 36 853
    Points
    36 853
    Par défaut Juste pour le fun
    Salut,

    En guise d'apéro, ce soir j'ai repris le code d'eyquem...
    En fait je voulais voir si "brute force" était aussi bourrin que çà
    Sur mon veau, je n'obtiens pas (du tout) les mêmes résultats.

    Dans quoi me suis pris les pieds?
    - W

    Code Python : 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
    #! /usr/bin/python
    # Encoding: iso-8859-1
    import os
    
    TESTFILE = 'xxxx/doc/bash.html'
    
    def check_file():
        """check we have something to catch"""
        lines_found = list()
        linecount = 0
        with open(TESTFILE, 'r') as f:
            for line in f.read().splitlines():
                linecount += 1
                if line.endswith(os.sep):
                    lines_found.append(line)
        print 'file has %d lines and %d lines ending with %s' %(
                linecount, len(lines_found), os.sep)
        return lines_found
    
    
    def brute_force():
        """Pythonic?"""
        lines_found = list()
        with open(TESTFILE, 'r') as f:
            for line in f.read().splitlines():
                if line.endswith(os.sep):
                    lines_found.append(line)
        return lines_found
    
    def brute_force_slice():
        """Slice looks to be a real winner"""
        lines_found = list()
        with open(TESTFILE, 'r') as f:
            for line in f.read().splitlines():
                if line[-2:-1] == os.sep:
                    lines_found.append(line)
        return lines_found
    
    
    def endswith_sep():
        """C Way, process line by line"""
        lines_found = list()
        with open(TESTFILE, 'r') as f:
            for line in f:
                if line.endswith (os.sep):
                    lines_found.append(line)
        return lines_found
    
    def slice_sep():
        """C Way, with slice"""
        lines_found = list()
        with open(TESTFILE, 'r') as f:
            for line in f:
                if line[-2:-1] == os.sep:
                    lines_found.append(line)
        return lines_found
    
    def slice_nosep():
        """C Way, slice & separator in local var"""
        y = os.sep
        lines_found = list()
        with open(TESTFILE, 'r') as f:
            for line in f:
                if line[-2:-1] == y:
                    lines_found.append(line)
        return lines_found
    
    
    if __name__ == '__main__':
        from timeit import Timer
        import operator
        COUNT = 20
        REPEAT = 5
        os.sep = 'e'  # mock separator
        check_file()
        names = ('brute_force', 'brute_force_slice', 'endswith_sep', 'slice_sep', 'slice_nosep' )
        results = list()
        better = float(sys.maxint)
        for name in names:
             t = Timer('%s()' % name, "from __main__ import %s" % name)
             try:
    #            ms = 1000 * t.timeit(number=COUNT) / COUNT
                 ms = 1000 * min(t.repeat(repeat=REPEAT, number=COUNT))/ COUNT
                 
             except:
                t.print_exc()
                sys.exit(1)
             print "%-20s : %0.3f Ms" % (name, ms )
             results.append((name, ms))
             if ms < better:
                 better = ms
             
        print '--- and the winner is: '
    
        for item in sorted(results,
                key=operator.itemgetter(1)):
            name, ms = item
            print "%-20s : %0.2f%%" % (name, ms/better )

    Résultats
    file has 11359 lines and 759 lines ending with e
    brute_force : 90.269 Ms
    brute_force_slice : 86.800 Ms
    endswith_sep : 87.240 Ms
    slice_sep : 91.892 Ms
    slice_nosep : 90.938 Ms
    --- and the winner is:
    brute_force_slice : 1.00%
    endswith_sep : 1.01%
    brute_force : 1.04%
    slice_nosep : 1.05%
    slice_sep : 1.06%

  9. #9
    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
    Bonjour,



    os.sep est aussi en mémoire vive.
    + 1
    Effectivement , c’est une constante, un attribut du module os, c’est à dire un composant de l’objet référencé par os, et non pas une fonction qui devrait rechercher la valeur de sep à chaque appel os.sep.

    Je suis donc d’acord: y = os.sep rend plus rapidement disponible os.sep que la succession de recherches:
    d’abord trouver le nom os dans le dictionnaire globals() pour connaître l’adresse de l’objet os, puis trouver l’objet os dans l’ensemble des objets présents en mémoire, puis chercher dans l’objet os le composant attribut sep. C’est ainsi que je vois les choses. Am I right ?

    Remarque: à mon avis, y n’est pas une variable locale, car il n’y a pas de fonctions dans mon code.





    Pour ce qui est de ln[-2:-1] et ln.endswith , je pense que tu as raison. Je ne m’étais jamais posé la question de la raison de la différence mais ça doit se passer comme tu dis:

    endswith() doit déterminer la longueur de l’argument qui lui est passé, déterminer aussi la longueur de la chaîne ln, soustraire ces deux longueurs et se placer à la bonne position de la chaîne pour lire ce qui est la fin à comparer avec l’argument. C’est plus long que de savoir directement quels sont les caractères à considérer dans la chaîne.

    C’est la même raison qui fait qu’il est très légèrement plus long pour l’interpréteur de trouver un ch[-7:] que ch[133:] dans une chaîne de longueur 140.



    -----------------------------------

    C’est le genre de trucs que je considère comme des acquis ordinaires dont je tiens un peu compte quand je fais un code parce que je me suis un jour amusé à faire des tests pour voir les différences de temps entre diverses possibilités pour une même action.
    Je me suis aperçu de choses du genre:
    - les fonctions comme endswith, partition, count... sont relativement lentes.
    - les instructions basées sur les indices sont très rapides
    - find est extrêmement rapide, plus rapide qu’une regex
    - les concaténations de chaînes par join() ou opérateur + sont plus rapides que du formatage de chaîne du genre “autoroute %s, sortie %s“ % (aut,sortie)
    etc

    Ça ne m’étonnerait pas non plus que l’une ou l’autre de ces conclusions ne soit pas toujours vérifiée, mais bon, je les prend globalement comme caractéristiques de base, et je continue d’en tenir compte. Pas de façon rigoriste et acharnée, mais parce que ça ne me demande qu’une énergie mentale supplémentaire minime.

    Au début de ma découverte de Python, je cherchais beaucoup plus systématiquement la meilleure tournure d’un code de façon à ce qu’il soit le plus rapide possible, poussant parfois les choses dans des contorsions sibyllines. J’ai pris conscience un jour que je codais en Python comme si je voulais en faire du C, et que c’était idiot parce que l’intérêt de Python est justement d’abandonner une seule prétention, la recherche de la plus grande vitesse possible, que mettent en avant les partisans de C++, pour élever le niveau sur plein d’autres aspects dont les plus importants sont lisibilité, rapidité de codage, maintenabilité aisée... tout ça parce que Python est du coté de l’abstraction, c’est à dire des pensées qui intéressent un humain quand il ressent le besoin d’utiliser l’informatique, et non pas du coté du matériel.

    Alors non, je ne suis pas désireux de faire du C++, et je suis bien content que Python existe et m’ait permis d’être capable de faire en une semaine d’apprentissage des programmes que j’aurais mis 8 mois à concevoir en C++.



    Ceci dit, il se trouve aussi que je pense important de ne pas perdre complétement de vue les fondements et les coulisses des choses, et que j’aime bien décortiquer les mécanismes sous-jacents. Alors j’ai encore le défaut de m’intéresser trop souvent à l’aspect mécanistique de codes, mais c’est sans penser que ce doit être une règle. Je considère tout à fait acceptable d’utiliser endswith() au lieu de jeu d’indice dans un code, la différence de temps ne sera pas énorme et ça le rend plus expressif. La différence de 14 % que j’ai obtenue ne m’apparaît plus aussi importante qu’elle m’apparaissait quand j’apprenais les rudiments de Python: on est loin d’une variation de 1 à 2 ou même de 1 à 10 ou 100 que l’on obtient par un changement d’algorithme dans certains cas. De toutes façons avec la rapidité des processeurs de nos jours, il n’y a aucune importance à voir tourner la plupart des codes en 4 millièmes de secondes plutôt qu’en 6 millièmes.

    Mais bon, j’aime bien les trucs techniques de détail. D’ailleurs je considère C différemment de C++. Pas du tout envie d’apprendre le C++. Mais je pense que c’est un gros plus de connaître C, pour comprendre comment ça se passe précisément au niveau mémoire et matériel, puisque Python est implémenté en C, et ce n’est pas par hasard à mon avis. Désolé si ma marotte donne l’impression que je suis perf-obsessionnel. C’est parce que je n’ai en réalité pas commencé à étudier sérieusement les richesses des modules élaborés et des applications existant en Python.

  10. #10
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 333
    Points : 36 853
    Points
    36 853
    Par défaut
    Arrête l'autoflagellation, c'est pas bon pour ce que tu as
    - W

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 04/11/2014, 15h36
  2. Comparer les lignes d'un fichier EXCEL
    Par eedas dans le forum Excel
    Réponses: 5
    Dernier message: 10/11/2013, 15h15
  3. Comparer les lignes d'un fichier .csv
    Par mario3979 dans le forum Shell et commandes GNU
    Réponses: 6
    Dernier message: 05/06/2012, 14h08
  4. Comparer les lignes d'un fichier txt
    Par Casimir* dans le forum VBScript
    Réponses: 3
    Dernier message: 28/08/2007, 15h12
  5. Réponses: 3
    Dernier message: 26/04/2004, 12h51

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