Як перетворити файл у словник?


94

У мене є файл, що складається з двох стовпців, тобто

1 a 
2 b 
3 c

Я хочу прочитати цей файл у словнику, щоб стовпець 1 був ключем, а стовпець 2 - значенням, тобто

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

Файл невеликий, тому ефективність не є проблемою.

Відповіді:


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

1
Не могли б ви пояснити це твердженням?
VGE

12
withвикористовується тут для обробки файлу очищення. Коли ви залишите блок (або просто за допомогою звичайного потоку виконання, або за винятком), файл буде автоматично закритий. Ви можете прочитати більше про контекстні менеджери в Python тут: effbot.org/zone/python-with-statement.htm
Влад H

1
for line in open("file.txt"):робити прибирання так само. І якщо f - місцеве значення, fвоно звільняється, коли область втрачається. Єдиний випадок, коли це твердження є корисним, це довга функція (не підходить для якості) або якщо ви використовуєте глобальну змінну.
VGE

1
@VGE, for line in open('file.txt')нічого НЕ робити Cleanup таким же чином. Не всі реалізації Python однакові. withгарантує, що файл буде закрито після виходу з блоку. Коли forлінія завершена, close може бути викликаний. CPythonце буде, але такі версії, як IronPythonліниві збирачі сміття.
Марк Толонен

2
Чи справді тут потрібен int? Можливо, він хотів, щоб цифри були рядками?
GL2014,

15

Після цього ключ залишиться як рядок:

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

2
Досить простого dict([line.split() for line in f]), іммо.
user225312

@sukhbir: якщо ви прочитаєте запитання, то побачите, що це не те, що хоче ОП.
SilentGhost

@SilentGhost: Я читав, що OP хоче ключі як цілі числа, але рішення Ігнасіо (як і те, яке я видалив), має ключі як рядок (як зазначив сам Ігнасіо).
user225312

Я був збентежений, чому нам не потрібно [], передаючи аргумент dict. тобто dict([x.rstrip().split(None, 1) for x in f])замість dict(x.rstrip().split(None, 1) for x in f). Для тих, хто думає про одне і те ж, перший є виразом генератора замість розуміння списку, як пояснено тут: python.org/dev/peps/pep-0289(PEP-289) . Дізнався щось нове!
peaxol

1
@peaxol: Ми використовуємо вираз генератора замість розуміння списку, щоб не створювати проміжний список.
Ігнасіо Васкес-Абрамс

7

Якщо у вашій версії python 2.7+, ви також можете використовувати розуміння дикту, наприклад:

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
чому ні partition? і withзаяву?
SilentGhost

@SilentGhost: Я не знав про розділ! але чому в цьому випадку краще str.split? щодо "with": можливо, ви можете мені це пояснити: чи недостатньо вийти за межі рамки, щоб закрити дескриптор файлу? Я думаю, у винятку файл main залишається відкритим, я його зміню.
Tokland

partitionшвидше і створено саме для цієї мети.
SilentGhost

незакрито дескриптор чи ні - це деталь реалізації. with- це простий спосіб переконатися, що він є.
SilentGhost

це все одно вимагало б strip, я б сказав.
SilentGhost

3

За розумінням словника

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

Або по пандах

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

Пандами бере лише перший стовпець
Маулік Мадхаві

1
@Samer Ayoub Вищевказане рішення (розуміння словника) працює, якщо і ключі, і значення мають одне слово. Якщо в моєму текстовому файлі є наступні дані. Як мені зробити рік ключовим, а команду-переможця - значеннями? 1903 Американці в Бостоні 1904 Немає світових серій 1905 Нью-Йоркські гіганти 1906 Чикаго Уайт Сокс 1907 Чикаго Дитинчата 1908 Чикаго Дитинчата
Кубс

1
@Ridhi Вибачте за запізнілу відповідь. Ви можете розділити на першому просторі лише stackoverflow.com/questions/30636248/… Або використовувати регулярний вираз як аргумент для split ()
Samer Ayoub

@ SamerAyoub- Дякую.
Рідхі,

1

IMHO трохи пітонічніше для використання генераторів (для цього, мабуть, потрібно 2.7+):

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

Це також відфільтрує рядки, які не починаються з цілого числа або не містять рівно два елементи


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? серйозно?
SilentGhost

Я не думаю, що це найкращий підхід.
Донован

@Seafoid сказав: "Файл невеликий, тому ефективність не є проблемою". split()не працює майже безшумно, якщо формат файлу відсутній.
VGE

0

Якщо ви любите один лайнер, спробуйте:

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

Вхідний ФАЙЛ = Шлях до файлу, SEP = Розділювач символів ключ-значення

Не найелегантніший чи найефективніший спосіб зробити це, але все ж досить цікаво :)


0

Ось ще один варіант ...

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

Простий варіант

Більшість методів для зберігання словника використовують JSON, Pickle або рядкове читання. Якщо ви не редагуєте словник за межами Python, цього простого методу вистачить навіть на складні словники. Хоча Pickle буде кращим для великих словників.

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.