Создание словаря из каждой строки в файле

Mr Helpme спросил: 28 апреля 2018 в 09:03 в: python

Я пытаюсь сделать словарь из этого файла: с ключом, являющимся первым словом, а значениями являются все слова после.

andrew fred
fred
judy andrew fred
george judy andrew
john george

Это код, который у меня есть :

follows_file = open("C:\\Users\\Desktop\\Python\\follows.txt")
followers = {}
for line in follows_file:   #==> [Judy Andrew Fred]
    users = line.split(' ')     #==> [Judy, andrew, Fred, ....]
    follower = users[0]     #==> [Judy]
    followed_by = users[1:] #==> [Andrew, Fred]    for user in followed_by:
        # Add the 'follower to the list of followers user
        if user not in followers:
            followers[user] = []
        followers[user].append(follower)
print(followers.items())

Когда я печатаю переменную follower и , за которой следует , они верны, но у меня возникают проблемы с добавлением их в словарь правильно; с этим будет вывод

dict_items([('fred\n', ['andrew', 'judy']), ('andrew', ['judy']), ('judy' ['george']), ('andrew\n', ['george']), ('george', ['john'])])

Мой желаемый результат будет

(Andrew[Fred])(Fred[])(judy[Andrew Fred])(George[Judy Fred])(john[george])

Любая помощь очень ценится!


4 ответа

Есть решение
thesilkworm ответил: 28 апреля 2018 в 10:04

Отредактированный ответ улучшился благодаря комментариям от @ PM2Ring и @ IljaEverilä.

Вот мое оригинальное решение, использующее понимание словаря

followers = {line.split()[0]: line.split()[1:] for line in follows_file}

Более эффективная альтернатива, предложенная @ IljaEverilä, которая позволяет дважды вызвать вызов split:

followers = {follower: followees for follower, *followees in map(str.split, follows_file)}

Результат:

{'andrew': ['fred'],
 'fred': [],
 'george': ['judy', 'andrew'],
 'john': ['george'],
 'judy': ['andrew', 'fred']}

Обратите внимание, что оба вышеупомянутых решения предполагают, что ваш файл не содержит дубликатов ключей.

Не забудьте закрыть файл после этого:

follows_file.close()

Или лучше, просто используйте диспетчер контекста, который обрабатывает файл, закрывающий для вас:

with open('C:\\Users\\zacan\\Desktop\\Python\\follows.txt', 'r') as follows_file:
    followers = {follower: followees for follower, *followees in map(str.split, follows_file)}
PM 2Ring ответил: 28 апреля 2018 в 09:37
Зачем вызывать .strip() строку, которую вы передаете в .split()? И зачем выполнять эти дорогостоящие операции дважды в каждой строке? Используйте правильный цикл for, поэтому вам не нужно это делать.
Ilja Everilä ответил: 28 апреля 2018 в 09:47
{follower: followees for follower, *followees in map(str.split, f)}
thesilkworm ответил: 28 апреля 2018 в 09:54
@ PM2Ring - я не понял, что split() позаботился о завершающем \n для каждой строки, отредактировал вызовы strip() из моего ответа. @ IljaEverilä, хорошо, я пытался подумать о том, как сделать понимание, не вызывая split() дважды, но не думал об этом.
zwer ответил: 28 апреля 2018 в 09:31

Вы можете использовать collections.defaultdict() в качестве фабрики словарей и просто добавлять пользователей, следующих за человеком, например:

import collectionsfollowers = collections.defaultdict(list)  # use a dict factory to save some time on checks
with open("path/to/your_file", "r") as f:  # open the file for reading
    for line in f:  # read the file line by line
        users = line.split()  # split on any white space
        followers[users[0]] += users[1:]  # append the followers for the current user

Что создаст для ваших данных:

{'andrew': ['fred'],
 'fred': [],
 'judy': ['andrew', 'fred'],
 'george': ['judy', 'andrew'],
 'john': ['george']}

Это также позволит вам добавить несколько списков к пользователю в повторяющейся записи - иначе вы можете просто использовать обычный dict для followers и установите их как followers[users[0]] = users[1:].

Структура данных, которую вы показали как ваш желаемый результат, недействительна Python, вы действительно хотите, чтобы она была представлена ​​именно так? Я имею в виду, если вы настаиваете, что можете сделать это как:

print("".join("({}[{}])".format(k, " ".join(v)) for k, v in followers.items()))
# (andrew[fred])(fred[])(judy[andrew fred])(george[judy andrew])(john[george])
jpp ответил: 28 апреля 2018 в 10:16

Это одно решение, использующее str.split и try / except для захвата экземпляров, в которых существует только ключ.

Примечание. io.StringIO позволяет нам читать из строки, как если бы это был файл.

from io import StringIO
import csvmystr = StringIO("""andrew fred
fred
judy andrew fred
george judy andrew
john george""")# replace mystr with open("C:\\Users\\zacan\\Desktop\\Python\\follows.txt")
with mystr as follows_file:
    d = {}
    for users in csv.reader(follows_file):
        try:
            key, *value = users[0].split()
        except ValueError:
            key, value = users[0], []        d[key] = valueprint(d){'andrew': ['fred'],
 'fred': [],
 'george': ['judy', 'andrew'],
 'john': ['george'],
 'judy': ['andrew', 'fred']}
M. Matt ответил: 28 апреля 2018 в 09:22
followers = dict()
with open('C:\\Users\\zacan\\Desktop\\Python\\follows.txt', 'r') as f:
    for line in f:
        users = line.split(' ')
        followers[users[0]] = [_ for _ in users[1:]]

это должно работать, не проверял его

zwer ответил: 28 апреля 2018 в 09:30
Нет абсолютно никаких оснований для понимания списка при настройке значения пользовательских подписчиков. Кроме того, line.split(' ') приведет к тому, что последний пользователь присоединится к \n, добавленному к нему, или зарегистрирует нового пользователя с \n в качестве последнего символа.