#python #dictionary
Вопрос:
У меня есть словарь, который выглядит так:
{'movies': ["1.nBram Stoker's Draculan(1992)",
'2.nDraculan(1931)',
'3.nHotel Transylvanian(2012)',
'4.nBlade: Trinityn(2004)',
'5.nDracula Untoldn(2014)',
'6.nThe Monster Squadn(1987)',
'7.nNosferatun(1922)',
'8.nHotel Transylvania 3n(2018)',
'9.nHotel Transylvania 2n(2015)']}
Я хотел разделить этот словарь на два отдельных ключа, например, как:
#expected output
{'movies': ["Bram Stoker's Dracula",
"Dracula" ...], 'year':[1992, 1931 ...]}
Я попробовал это, которое должно было выбрать для строк, принадлежащих после n
:
result = {}
for k,v in movies.items():
result[k] = movies[k].lower().replace(' ', '_').split('n')
но я получаю ошибку:
объект «список» не имеет атрибута «ниже»
Комментарии:
1. Ожидаемый вывод-неверный синтаксис, не могли бы вы исправить его без сокращений, чтобы было понятно?
Ответ №1:
movies
разве список — это не диктат:
Предположим, что этот вход:
d1 = {'movies': ["1.nBram Stoker's Draculan(1992)",
'2.nDraculan(1931)',
'3.nHotel Transylvanian(2012)',
'4.nBlade: Trinityn(2004)',
'5.nDracula Untoldn(2014)',
'6.nThe Monster Squadn(1987)',
'7.nNosferatun(1922)',
'8.nHotel Transylvania 3n(2018)',
'9.nHotel Transylvania 2n(2015)']}
Создайте диктант для хранения извлеченных данных:
d2 = {'movies': [], 'year': []}
for row in d1['movies']:
_, movie, year = row.split('n')
d2['movies'].append(movie)
d2['year'].append(int(year[1:-1]))
Никакого теста не проводится. Я думаю, что все строки имеют один и тот же формат
Результат вывода:
>>> d2
'Dracula',
'Hotel Transylvania',
'Blade: Trinity',
'Dracula Untold',
'The Monster Squad',
'Nosferatu',
'Hotel Transylvania 3',
'Hotel Transylvania 2'],
'year': [1992, 1931, 2012, 2004, 2014, 1987, 1922, 2018, 2015]}
Обновить
Более надежная версия с регулярным выражением:
import re
d2 = {'movies': [], 'year': []}
for row in d1['movies']:
sre = re.search(r'd.n(.*)(?:n?((d )))?', row)
movie = sre.group(1)
year = int(sre.group(2)) if sre.group(2) else float('nan')
d2['movies'].append(movie)
d2['year'].append(year)
Комментарии:
1. Кажется, я получаю следующую ошибку, когда запускаю ее в своем скрипте, который следует той же последовательности, что и список, но с 50 значениями; Ошибка
not enough values to unpack (expected 3, got 2)
во второй строке цикла for_, movie, year = row.split('n')
2. Я думаю, что нашел ошибку , в одной из строк отсутствует дополнительная
n
, есть ли способ заполнить соответствующую строку в столбце » год » значением, например,N/A
когда это произойдет?
Ответ №2:
Я бы, вероятно, использовал регулярные выражения для решения такого рода задачи сопоставления шаблонов. В приведенном ниже примере название и год отображаются в группах.
import re
movie_pattern = re.compile(r"[0-9] .n([^n] )n(([0-9] ))")
movies_dict = {
...
}
split_dict = {"titles": [], "years": []}
for movie in movies_dict["movies"]:
match = movie_pattern.fullmatch(movie)
split_dict["titles"].append(match[1])
split_dict["years"].append(int(match[2]))
print(split_dict)
Объяснение:
[0-9] .
: Одна или несколько цифр, представляющих индекс, за которыми следует литерал .
n
: Буквальный n
([^n] )
: Один или несколько символов новой строки, представляющих заголовок, в группе захвата
n
: Буквальный n
(
: Буквальный (
([0-9] )
: Одна или несколько цифр, представляющих год, в группе захвата
)
: Буквальный )
Изменить: чтобы обработать случай, который вы упомянули в своем комментарии, где иногда отсутствует год, вместо этого вы можете использовать следующий шаблон:
movie_pattern = re.compile(r"[0-9] .n([^n] )(?:n(([0-9] )))?")
(?:)
Это группа без захвата, а ?
затем означает, что группа необязательна.
Затем, если год отсутствует, значение группы захвата равно None
, с которой вы можете обращаться следующим образом:
for movie in movies_dict["movies"]:
match = movie_pattern.fullmatch(movie)
title = match[1]
year = match[2]
if year is not None:
year = int(year)
split_dict["titles"].append(title)
split_dict["years"].append(year)
Так что, если movies_dict
выглядит так
movies_dict = {
"movies": [
...,
"9.nHotel Transylvania 2", # only one newline, no year
],
}
тогда результат будет
{
"titles": [..., "Hotel Transylvania 2"],
"years": [..., None],
}
Ответ №3:
Для развлечения, вот решение в виде понимания списка (при movies_dict
условии, что в качестве входных данных):
dict(zip(['movies', 'year'], zip(*[(a, int(b[1:-1]))
for i in movies_dict['movies']
for a,b in [i.split('n')[1:]]
])))
выход:
{'movies': ("Bram Stoker's Dracula",
'Dracula',
'Hotel Transylvania',
'Blade: Trinity',
'Dracula Untold',
'The Monster Squad',
'Nosferatu',
'Hotel Transylvania 3',
'Hotel Transylvania 2'),
'year': (1992, 1931, 2012, 2004, 2014, 1987, 1922, 2018, 2015)}