Как создать словарь, используя один список?
У меня есть список URL и заголовков с сайта газеты в моей стране. Как общий пример:
x = ['URL1','news1','news2','news3','URL2','news1','news2','URL3','news1']
Каждый элемент URL имеет соответствующую последовательность элементов "новости", которые могут различаться по длине. В приведенном выше примере URL1 имеет 3 соответствующие новости, а URL3 - только одну.
Иногда URL не имеет соответствующего элемента "новости":
y = ['URL4','news1','news2','URL5','URL6','news1']
Я легко могу найти каждый индекс URL и элементы "новости" каждого URL.
У меня такой вопрос: Возможно ли преобразовать этот список в словарь, в котором элемент URL является ключом, а элементы "news" - значением списка/кортежа?
Ожидаемый результат
z = {'URL1':('news1', 'news2', 'news3'),
'URL2':('news1', 'news2'),
'URL3':('news1'),
'URL4':('news1', 'news2'),
'URL5':(),
'URL6':('news1')}
Я видел похожий вопрос в этом сообщении, но он не решил мою проблему.
Ответы
Ответ 1
Вы можете сделать это так:
>>> y = ['URL4','news1','news2','URL5','URL6','news1']
>>> result = {}
>>> current_url = None
>>> for entry in y:
... if entry.startswith('URL'):
... current_url = entry
... result[current_url] = ()
... else:
... result[current_url] += (entry, )
...
>>> result
{'URL4': ('news1', 'news2'), 'URL5': (), 'URL6': ('news1',)}
Ответ 2
Вы можете использовать itertools.groupby
с функцией key
для идентификации URL:
from itertools import groupby
def _key(url):
return url.startswith("URL") #in the body of _key, write code to identify a URL
data = ['URL1','news1','news2','news3','URL2','news1','news2','URL3','news1', 'URL4','news1','news2','URL5','URL6','news1']
new_d = [list(b) for _, b in groupby(data, key=_key)]
grouped = [[new_d[i], tuple(new_d[i+1])] for i in range(0, len(new_d), 2)]
result = dict([i for [*c, a], b in grouped for i in [(i, ()) for i in c]+[(a, b)]])
Выход:
{
'URL1': ('news1', 'news2', 'news3'),
'URL2': ('news1', 'news2'),
'URL3': ('news1',),
'URL4': ('news1', 'news2'),
'URL5': (),
'URL6': ('news1',)
}
Ответ 3
Вы можете просто использовать индексы URL-ключей в списке и получить то, что находится между индексами, и назначить первый
Как это:
x = ['URL1','news1','news2','news3','URL2','news1','news2','URL3','news1']
urls = [x.index(y) for y in x if 'URL' in y]
adict = {}
for i in range(0, len(urls)):
if i == len(urls)-1:
adict[x[urls[i]]] = x[urls[i]+1:len(x)]
else:
adict[x[urls[i]]] = x[urls[i]+1:urls[i+1]]
print(adict)
выход:
{'URL1': ['news1', 'news2', 'news3'], 'URL2': ['news1', 'news2'], 'URL3': ['news1']}
Ответ 4
библиотека more-itertools содержит функцию split_before()
, которая очень удобна для этой цели:
{s[0]: tuple(s[1:]) for s in mt.split_before(x, lambda e: e.startswith('URL'))}
Я думаю, что это чище, чем любой другой подход в ответах, опубликованных до этого, но он вводит внешнюю зависимость (если вы не переопределите функцию), что делает ее не подходящей для каждой ситуации.
Если ваш реальный вариант использования включает в себя реальные URL или что-то еще, а не строки вида URL#
, просто замените lambda e: e.startswith('URL')
любой функцией, которую вы можете использовать для выбора ключевых элементов, кроме элементов значения.
Ответ 5
Другое решение, использующее groupby
, однострочное:
x = ['URL1','news1','news2','news3','URL2','news1','news2','URL3','news1', 'URL4','news1','news2','URL5','URL6','news1']
from itertools import groupby
out = {k: tuple(v) for _, (k, *v) in groupby(x, lambda k, d={'g':0}: (d.update(g=d['g']+1), d['g']) if k.startswith('URL') else (None, d['g']))}
from pprint import pprint
pprint(out)
Печать:
{'URL1': ('news1', 'news2', 'news3'),
'URL2': ('news1', 'news2'),
'URL3': ('news1',),
'URL4': ('news1', 'news2'),
'URL5': (),
'URL6': ('news1',)}