Como converter um arquivo em um dicionário?

93

Eu tenho um arquivo composto por duas colunas, ou seja,

1 a 
2 b 
3 c

Desejo ler este arquivo para um dicionário de forma que a coluna 1 seja a chave e a coluna 2 seja o valor, ou seja,

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

O arquivo é pequeno, portanto a eficiência não é um problema.

Darren J. Fitzpatrick
fonte

Respostas:

153
d = {}
with open("file.txt") as f:
    for line in f:
       (key, val) = line.split()
       d[int(key)] = val
Vlad H
fonte
1
Você poderia explicar a declaração com?
VGE
12
withé usado aqui para lidar com a limpeza do arquivo. Quando você sai do bloco (seja apenas pelo fluxo de execução normal ou por uma exceção), o arquivo será fechado automaticamente. Você pode ler mais sobre gerenciadores de contexto em Python aqui: effbot.org/zone/python-with-statement.htm
Vlad H
1
for line in open("file.txt"):faça a limpeza da mesma maneira. E se f for um valor local, o fserá liberado quando o escopo for perdido. O único caso em que essa instrução é útil é para função longa (não é boa para qualidade) ou se você usar uma variável global.
VGE de
1
@VGE, for line in open('file.txt')se não fazer a limpeza da mesma maneira. Nem todas as implementações Python são iguais. withgarante que o arquivo será fechado quando o bloco for encerrado. Quando a forlinha estiver completa, close pode ser chamado. CPythonvai, mas versões como IronPythontêm coletores de lixo preguiçosos.
Mark Tolonen,
2
É realmente necessário aqui? Talvez ele quisesse que os números fossem strings?
GL2014
15

Isso deixará a chave como uma string:

with open('infile.txt') as f:
  d = dict(x.rstrip().split(None, 1) for x in f)
Ignacio Vazquez-Abrams
fonte
2
Um simples dict([line.split() for line in f])é suficiente, imo.
user225312
@sukhbir: se você ler a pergunta, verá que não é isso que op deseja.
SilentGhost
@SilentGhost: Eu li que o OP quer as chaves como inteiros, mas a solução de Ignacio (assim como a que eu apaguei) tem as chaves como uma string (como apontado pelo próprio Ignacio).
user225312
Fiquei confuso por que não precisamos [] ao passar o argumento dict. ou seja, em dict([x.rstrip().split(None, 1) for x in f])vez de dict(x.rstrip().split(None, 1) for x in f). Para aqueles que pensam a mesma coisa, a primeira é uma expressão geradora em vez de compreensão de lista, conforme explicado aqui: python.org/dev/peps/pep-0289(PEP-289) . Aprendeu algo novo!
peaxol
1
@peaxol: Usamos uma expressão geradora em vez de uma compreensão de lista para não criar uma lista intermediária.
Ignacio Vazquez-Abrams
7

Se sua versão python for 2.7+, você também pode usar uma compreensão de dicionário como:

with open('infile.txt') as f:
  {int(k): v for line in f for (k, v) in (line.strip().split(None, 1),)}
wim
fonte
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)
Tokland
fonte
1
por que não partition? e withdeclaração?
SilentGhost
@SilentGhost: Eu não sabia sobre partição! mas por que é melhor str.split neste caso? em relação a "com": talvez você possa esclarecer isso para mim: não é suficiente sair do escopo para que o descritor de arquivo seja fechado? Acho que em uma exceção o arquivo principal permanece aberto, vou alterá-lo.
tokland
partitioné mais rápido e é criado exatamente para esse propósito.
SilentGhost
se o descritor está fechado ou não é um detalhe de implementação. withé uma maneira simples de garantir que sim.
SilentGhost
ainda exigiria strip, eu diria.
SilentGhost
3

Por compreensão de dicionário

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

Ou por pandas

import pandas as pd 
d = pd.read_csv("file.txt", delimiter=" ", header = None).to_dict()[0]
Samer Ayoub
fonte
Por pandas ocupa apenas a primeira coluna
Maulik Madhavi
1
@Samer Ayoub A solução acima (compreensão do dicionário) funciona se as chaves e o valor tiverem uma palavra. Se meu arquivo de texto contém os seguintes dados. Como faço para fazer o ano como chaves e equipe vencedora como valores. 1903 Boston americanos 1904 No World Series 1905 New York Giants 1906 Chicago White Sox 1907 Chicago Cubs 1908 Chicago Cubs
Ridhi
1
@Ridhi Desculpe pela resposta tardia. Você pode dividir no primeiro espaço apenas stackoverflow.com/questions/30636248/… Ou usar uma expressão regular como argumento para split ()
Samer Ayoub
@ SamerAyoub- Obrigado.
Ridhi
1

IMHO um pouco mais pitônico para usar geradores (provavelmente você precisa de 2.7+ para isso):

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()}

Isso também irá filtrar as linhas que não começam com um número inteiro ou não contêm exatamente dois itens

Holger Bille
fonte
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)
VGE
fonte
9
re? seriamente?
SilentGhost
Não acho que seja a melhor abordagem.
Donovan
@Seafoid disse "O arquivo é pequeno, então a eficiência não é um problema." split()não funciona quase silenciosamente se o formato do arquivo não for adequado.
VGE
0

Se você adora um liners, tente:

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

Input FILE = Caminho para o arquivo, SEP = caractere separador de valor-chave

Não é a maneira mais elegante ou eficiente de fazer isso, mas muito interessante, no entanto :)

srami
fonte
0

Aqui está outra opção ...

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:]
Robel Robel Lingstuyl
fonte
0

Opção Simples

A maioria dos métodos para armazenar um dicionário usa JSON, Pickle ou leitura de linha. Desde que você não esteja editando o dicionário fora do Python, este método simples deve ser suficiente até mesmo para dicionários complexos. Embora Pickle seja melhor para dicionários maiores.

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
A. West
fonte