2009-11-12 6 views
1

Quand je fais la compréhension de la liste ci-dessous je me retrouve avec des listes imbriquées:Comment diviser le contenu du fichier par l'espace et le caractère de fin de ligne?

channel_values = [x for x in [ y.split(' ') for y in 
    open(channel_output_file).readlines() ] if x and not x == '\n'] 

Fondamentalement, j'ai un fichier composé de ceci:

7656 7653 7649 7646 7643 7640 7637 7634 7631 7627 7624 7621 7618 7615 
8626 8623 8620 8617 8614 8610 8607 8604 8600 8597 8594 8597 8594 4444 
<snip several thousand lines> 

chaque ligne de ce fichier se termine par un nouveau ligne.

Fondamentalement, j'ai besoin d'ajouter chaque nombre (ils sont tous séparés par un seul espace) dans une liste.

Existe-t-il une meilleure façon de le faire via la compréhension de la liste?

Répondre

14

Vous n'avez pas besoin pour cette liste compréhensions:

channel_values = open(channel_output_file).read().split() 
+0

+1, Tu me devança –

5

Il suffit de faire ceci:

channel_values = open(channel_output_file).read().split() 

split() se partageront selon des espaces qui comprend ' ' '\t' and '\n'. Il divisera toutes les valeurs en une seule liste.

Si vous voulez des valeurs entières que vous pouvez faire:

channel_values = map(int, open(channel_output_file).read().split()) 

ou avec la liste compréhensions:

channel_values = [int(x) for x in open(channel_output_file).read().split()] 
0

Eh bien un autre problème est que vous quittez le fichier ouvert. Notez que open est un alias pour file.

essayez ceci:

f = file(channel_output_file) 
channel_values = f.read().split() 
f.close() 

Notez qu'ils seront les valeurs de chaîne si vous voulez les entiers changent la deuxième ligne à

channel_values = [int(x) for x in f.read().split()] 

int (x) va lancer une ValueError si vous avez une valeur non entière dans le fichier.

+0

Je pensais que les dossiers ont été fermés automatiquement une fois que vous avez quitté la portée de la compréhension de la liste? – UberJumper

+1

L'objet fichier est fermé lorsqu'il est collecté et qu'il est collecté lorsqu'il n'y a aucune référence. Donc non, il ne laisse pas le fichier ouvert, car il n'y a pas de références après l'exécution de la ligne. –

+0

Merci, j'ai été inquiet pendant une seconde :) – UberJumper

2

En outre, la raison pour laquelle la liste d'origine avait une liste imbriquée est que vous avez ajouté un niveau supplémentaire de compréhension de liste avec l'ensemble interne de crochets. Vous vouliez dire ceci:

channel_values = [x for x in y.split(' ') for y in 
    open(channel_output_file) if x and not x == '\n'] 

Les autres réponses sont encore meilleures façons d'écrire le code, mais qui a été la cause du problème.

+0

Vous aviez ceci comme 'open (channel_output_file) .readlines()' mais tout ce dont vous avez vraiment besoin est 'open (channel_output_file)'. L'objet fichier renvoyé par 'open()' fonctionne comme un itérateur qui retourne des lignes; 'readlines()' slurp dans chaque ligne, ce qui n'est pas nécessaire ici. J'ai édité votre code pour enlever le "readlines()". Aussi voté vous +1. – steveha

+0

Cela échouera parce que vous avez mélangé l'ordre de "for x in ..." et "for y in ...". La syntaxe de compréhension de liste imbriquée de Python est contre-intuitive à moins que vous ne vous rappeliez qu'elle imite l'ordre dans lequel vous auriez raison pour vos boucles sans compréhension. Aussi, pourquoi ne pas simplement scinder() et passer le test pour newline? –

+0

(espérons que ce commentaire ne semble pas plus d'une fois - excuses si c'est le cas) Point pris de l'ordre de x et y, merci! C'est très déroutant. La raison pour laquelle je suis parti dans split(), et readlines() que Steve a supprimée, était de montrer ce qui causait le problème avec les listes imbriquées en faisant la plus petite modification possible au code original. Lukáš et Nadia avaient déjà montré comment améliorer le code. –

0

Existe-t-il une meilleure façon de le faire via la compréhension de la liste?

Type de ..

Au lieu de lire chaque ligne comme un tableau, avec les méthodes .readlines(), vous pouvez simplement utiliser .read():

channel_values = [x for x in open(channel_output_file).readlines().split(' ') 
if x not in [' ', '\n']] 

Si vous avez besoin de faire quoi que ce soit plus compliqué, surtout si elle implique plusieurs liste-compréhensions, vous Il est presque toujours préférable de l'étendre dans une boucle régulière for.

out = [] 
for y in open(channel_output_file).readlines(): 
    for x in y.split(' '): 
     if x not in [' ', '\n']: 
      out.append(x) 

ou en utilisant une boucle et une liste-compréhension:

out = [] 
for y in open(channel_output_file).readlines(): 
    out.extend(
     [x for x in y.split(' ') 
     if x != ' ' and x != '\n']) 

Fondamentalement, si vous ne pouvez pas faire quelque chose simplement avec une compréhension de la liste (ou besoin de les nids), liste-compréhensions ne sont probablement pas la meilleure solution.

0

Si vous ne se soucient pas de références de fichiers ballants, et vous vraiment devez avoir une liste lu en mémoire à la fois, celui-liner mentionné dans d'autres réponses fonctionne:

channel_values = open(channel_output_path).read().split() 

Dans le code de production , J'utiliserais probablement un générateur, pourquoi lire toutes ces lignes si vous n'en avez pas besoin?

def generate_values_for_filename(filename): 
    with open(filename) as f: 
     for line in f: 
      for value in line.split(): 
       yield value 

Vous pouvez toujours faire une liste plus tard si vous avez vraiment besoin de faire autre chose que itérer sur les valeurs:

channel_values = list(generate_values_for_filename(channel_output_path))