Come convertire un file in un dizionario?


94

Ho un file composto da due colonne, ovvero

1 a 
2 b 
3 c

Desidero leggere questo file in un dizionario in modo tale che la colonna 1 sia la chiave e la colonna 2 il valore, ovvero

d = {1:'a', 2:'b', 3:'c'}

Il file è piccolo, quindi l'efficienza non è un problema.

Risposte:


154
d = {}
with open("file.txt") as f:
    for line in f:
       (key, val) = line.split()
       d[int(key)] = val

1
Potresti spiegare la dichiarazione with?
VGE

12
withviene utilizzato qui per gestire la pulizia del file. Quando si lascia il blocco (o solo per il normale flusso di esecuzione o per un'eccezione) il file verrà automaticamente chiuso. Puoi leggere di più sui gestori di contesto in Python qui: effbot.org/zone/python-with-statement.htm
Vlad H

1
for line in open("file.txt"):fai la pulizia allo stesso modo. E se f è un valore locale, fviene rilasciato quando l'ambito viene perso. L'unico caso in cui questa istruzione è utile è per la funzione lunga (non buona per la qualità) o se si utilizza una variabile globale.
VGE

1
@VGE, for line in open('file.txt')non senza fare pulizia allo stesso modo. Non tutte le implementazioni di Python sono le stesse. withgarantisce la chiusura del file quando si esce dal blocco. Quando la forlinea è completa, close può essere chiamato. CPythonlo farà, ma versioni come quelle IronPythonhanno lazy garbage collector.
Mark Tolonen

2
È davvero necessario int qui? Forse voleva che i numeri fossero stringhe?
GL2014

15

Questo lascerà la chiave come una stringa:

with open('infile.txt') as f:
  d = dict(x.rstrip().split(None, 1) for x in f)

2
Un semplice dict([line.split() for line in f])è sufficiente, imo.
user225312

@sukhbir: se leggi la domanda, vedrai che non è quello che vuole op.
SilentGhost

@ SilentGhost: ho letto che l'OP vuole le chiavi come numeri interi, ma la soluzione di Ignacio (così come quella che ho eliminato), ha le chiavi come stringa (come sottolineato dallo stesso Ignacio).
user225312

Ero confuso sul motivo per cui non abbiamo bisogno di [] quando si passa l'argomento dict. cioè dict([x.rstrip().split(None, 1) for x in f])invece di dict(x.rstrip().split(None, 1) for x in f). Per coloro che pensano la stessa cosa, la prima è un'espressione del generatore invece della comprensione delle liste come spiegato qui: python.org/dev/peps/pep-0289(PEP-289) . Ho imparato qualcosa di nuovo!
peaxol

1
@peaxol: usiamo un'espressione del generatore invece di una comprensione della lista per non creare una lista intermedia.
Ignacio Vazquez-Abrams

7

Se la tua versione di python è 2.7+, puoi anche utilizzare una comprensione dei dettami come:

with open('infile.txt') as f:
  {int(k): v for line in f for (k, v) in (line.strip().split(None, 1),)}

5
def get_pair(line):
    key, sep, value = line.strip().partition(" ")
    return int(key), value

with open("file.txt") as fd:    
    d = dict(get_pair(line) for line in fd)

1
perchè no partition? e withdichiarazione?
SilentGhost

@ SilentGhost: non sapevo della partizione! ma perché è meglio str.split in questo caso? per quanto riguarda "con": forse mi puoi chiarire questo: non basta uscire dall'ambito per chiudere il descrittore di file? Immagino che in un'eccezione il file principale rimanga aperto, lo cambierò.
Tokland

partitionè più veloce e viene creato esattamente per questo scopo.
SilentGhost

se il descrittore è chiuso o meno è un dettaglio di implementazione. withè un modo semplice per assicurarsi che lo sia.
SilentGhost

sarebbe ancora necessario strip, direi.
SilentGhost

3

Per comprensione del dizionario

d = { line.split()[0] : line.split()[1] for line in open("file.txt") }

O dai panda

import pandas as pd 
d = pd.read_csv("file.txt", delimiter=" ", header = None).to_dict()[0]

Di panda prende solo la prima colonna
Maulik Madhavi

1
@Samer Ayoub La soluzione sopra (comprensione del dizionario) funziona se entrambe le chiavi e il valore sono lunghe una parola. Se il mio file di testo ha i seguenti dati, come faccio a considerare l'anno come chiavi e la squadra vincente come valori. 1903 Boston Americans 1904 No World Series 1905 New York Giants 1906 Chicago White Sox 1907 Chicago Cubs 1908 Chicago Cubs
Ridhi

1
@Ridhi Scusa per la risposta tardiva. Puoi dividere sul primo spazio solo stackoverflow.com/questions/30636248/… Oppure utilizzare un'espressione regolare come argomento per split ()
Samer Ayoub

@ SamerAyoub- Grazie.
Ridhi

1

IMHO un po 'più pitonico per usare i generatori (probabilmente hai bisogno di 2.7+ per questo):

with open('infile.txt') as fd:
    pairs = (line.split(None) for line in fd)
    res   = {int(pair[0]):pair[1] for pair in pairs if len(pair) == 2 and pair[0].isdigit()}

Questo filtrerà anche le righe che non iniziano con un numero intero o che non contengono esattamente due elementi


0
import re

my_file = open('file.txt','r')
d = {}
for i in my_file:
  g = re.search(r'(\d+)\s+(.*)', i) # glob line containing an int and a string
  d[int(g.group(1))] = g.group(2)

9
re? sul serio?
SilentGhost

Non credo che questo sia l'approccio migliore.
Donovan

@ Seafoid ha detto "Il file è piccolo, quindi l'efficienza non è un problema." split()non funziona quasi in silenzio se il formato del file non è corretto.
VGE

0

Se ami le battute, prova:

d=eval('{'+re.sub('\'[\s]*?\'','\':\'',re.sub(r'([^'+input('SEP: ')+',]+)','\''+r'\1'+'\'',open(input('FILE: ')).read().rstrip('\n').replace('\n',',')))+'}')

Input FILE = percorso del file, SEP = carattere separatore valore-chiave

Non è il modo più elegante o efficiente per farlo, ma comunque piuttosto interessante :)


0

Ecco un'altra opzione ...

events = {}
for line in csv.reader(open(os.path.join(path, 'events.txt'), "rb")):
    if line[0][0] == "#":
        continue
    events[line[0]] = line[1] if len(line) == 2 else line[1:]

0

Opzione semplice

La maggior parte dei metodi per memorizzare un dizionario utilizza JSON, Pickle o la lettura di righe. A condizione che tu non stia modificando il dizionario al di fuori di Python, questo semplice metodo dovrebbe essere sufficiente per dizionari anche complessi. Sebbene Pickle sarà migliore per dizionari più grandi.

x = {1:'a', 2:'b', 3:'c'}
f = 'file.txt'
print(x, file=open(f,'w'))    # file.txt >>> {1:'a', 2:'b', 3:'c'}
y = eval(open(f,'r').read())
print(x==y)                   # >>> True
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.