Разделите новые строки на отдельные клавиши

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