3 votes

Lecture de deux lignes à la fois à partir de deux fichiers différents en Python

J'ai deux fichiers comme indiqué ci-dessous :

Fichier 1 (délimité par des tabulations) :

A1   someinfo1     someinfo2    someinfo3
A1   someinfo1     someinfo2    someinfo3
B1   someinfo1     someinfo2    someinfo3
B1   someinfo1     someinfo2    someinfo3

Fichier 2 (délimité par des tabulations) :

A1   newinfo1     newinfo2    newinfo3
A1   newinfo1     newinfo2    newinfo3
B1   newinfo1     newinfo2    newinfo3
B1   newinfo1     newinfo2    newinfo3

Je veux lire deux lignes ensemble (lignes commençant par A1 et A1) du fichier 1 et deux lignes (lignes commençant par A1 et A1) du fichier 2. Pour être plus clair, j'ai deux exigences :

1) Reading two lines from the same file
2) Read same two lines from the other file.  

Pour être précis, je veux lire quatre lignes ensemble ( 2 lignes consécutives de deux fichiers (2 lignes de chaque fichier)).

J'ai fait des recherches en ligne et j'ai pu obtenir un code pour lire deux lignes ensemble, mais seulement à partir d'un seul fichier.

with open(File1) as file1:
        for line1,line2 in itertools.izip\_longest(\*\[file1\]\*2):

J'ai également pu lire une ligne de chacun des deux fichiers comme :

for i,(line1,line2) in enumerate(itertools.izip(f1,f2)):
        print line1, line2

Mais je veux faire quelque chose comme :

Pseudocode :

for line1, line2 from file1 and line\_1 and line\_2 from file2:
              compare line1 with line2
              compare line1 with line\_1
              compare line2 with line\_1
              compare line2 with line\_2

J'espère que la solution sera un temps linéaire. Tous les fichiers ont le même nombre de lignes et la première colonne (id primaire) est la même pour les lignes consécutives dans un fichier et les autres fichiers suivent le même ordre (voir l'exemple ci-dessus).

Merci.

6voto

Pavel Anossov Points 23610

Que dites-vous de ça ?

with open('a') as A, open('b') as B:
    while True:
        try:
            lineA1, lineA2, lineB1, lineB2 = next(A), next(A), next(B), next(B)
            # compare lines
            # ...
        except StopIteration:
            break

1voto

abarnert Points 94246

Voyons comment nous pouvons les assembler. D'abord :

with open(File1) as file1:
    for line1,line2 in itertools.izip_longest(*[file1]*2):

Eh bien, enlevez le for et vous avez un itérateur de 2 lignes à la fois sur file n'est-ce pas ? Donc, tu peux faire la même chose pour file2 . Et ensuite vous pouvez zip ensemble :

with open(File1) as file1, open(File2) as file2:
    f1 = itertools.izip_longest(*[file1]*2)
    f2 = itertools.izip_longest(*[file2]*2)
    for i,((f1_line1, f1_line2), (f2_line1, f2_line2)) in enumerate(itertools.izip(f1,f2)):
        # do stuff

Mais tu ne veux vraiment pas faire ça.

Tout d'abord, la plupart des gens ne lisent pas intuitivement izip_longest(*[file1]*2) et réaliser que c'est un regroupement par paires. Enveloppez cela dans une fonction. En fait, n'écrivez même pas la fonction vous-même ; prenez la fonction grouper dès la sortie du documentation itertools .

Donc maintenant, c'est :

with open(File1) as file1, open(File2) as file2:
    pairs1 = grouper(2, file1)
    pairs2 = grouper(2, file2)
    for i,((f1_line1, f1_line2), (f2_line1, f2_line2)) in enumerate(itertools.izip(f1,f2)):
        # do stuff

Ensuite, le filtrage de motifs est peut-être cool, mais un motif imbriqué à décomposer au beau milieu d'une expression compliquée, c'est un peu trop. Alors, décomposons le tout, et désimbriquons les choses en empruntant flatten de la itertools docs à nouveau :

with open(File1) as file1, open(File2) as file2:
    pairs1 = grouper(2, file1)
    pairs2 = grouper(2, file2)
    zipped_pairs = itertools.izip(pairs1, pairs2)
    for i, zipped_pair in enumerate(zipped_pairs):
        f1_line1, f1_line2, f2_line1, f2_line2 = flatten(zipped_pair)
        # do stuff

L'avantage de cette solution est qu'elle est abstraite et générique, ce qui signifie que si vous décidez plus tard que vous avez besoin de groupes de 5 lignes, ou de 3 fichiers, le changement est évident.

L'inconvénient de cette solution est qu'elle est abstraite et générique, ce qui signifie qu'elle ne peut pas être aussi simple que l'équivalent concret. (Par exemple, si vous n'avez pas zip une paire de grouper vous n'auriez pas à flatten le résultat).

1voto

gnibbler Points 103484
>>> from itertools import izip
>>> with open("file1") as file1, open("file2") as file2:
...     for a1, a2, b1, b2 in izip(file1, file1, file2, file2):
...         print a1, a2, b1, b2
... 
A1   someinfo1     someinfo2    someinfo3
A1   someinfo1     someinfo2    someinfo3
A1   newinfo1     newinfo2    newinfo3
A1   newinfo1     newinfo2    newinfo3

B1   someinfo1     someinfo2    someinfo3
B1   someinfo1     someinfo2    someinfo3
B1   newinfo1     newinfo2    newinfo3
B1   newinfo1     newinfo2    newinfo3

Vous puede faire du nombre de lignes un paramètre ( n ) comme ceci

for lines in izip(*[file1]*n+[file2]*n):

maintenant les lignes seront un tuple avec n*2 éléments

0voto

J.F. Sebastian Points 102961

Voici une généralisation qui permet un nombre quelconque de lignes consécutives avec la même colonne id :

from itertools import groupby, izip, product

getid = lambda line: line.partition(" ")[0] # first space-separated column
same_id = lambda lines: groupby(lines, key=getid)

with open(File1) as file1, open(File2) as file2:
     for (id1, lines1), (id2, lines2) in izip(same_id(file1), same_id(file2)):
         if id1 != id2: 
            # handle error here
            break
         # compare all possible combinations
         for a, b in product(lines1, lines2): 
             compare(a, b)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X