python - ¿Cómo crear un diccionario usando una sola lista?
dictionary (5)
La
biblioteca more-itertools
contiene una función
split_before()
que es muy útil para este propósito:
{s[0]: tuple(s[1:]) for s in mt.split_before(x, lambda e: e.startswith(''URL''))}
Creo que esto es más limpio que cualquiera de los otros enfoques en las respuestas publicadas antes de este, pero introduce una dependencia externa (a menos que vuelva a implementar la función), lo que hace que no sea apropiado para cada situación.
Si su caso de uso real incluye URL reales o algo más, en lugar de cadenas del formulario
URL#
, simplemente reemplace
lambda e: e.startswith(''URL'')
con cualquier función que pueda usar para seleccionar los elementos clave aparte del valor elementos.
Tengo una lista de url y encabezados de un sitio de periódicos en mi país. Como ejemplo general:
x = [''URL1'',''news1'',''news2'',''news3'',''URL2'',''news1'',''news2'',''URL3'',''news1'']
Cada elemento de URL tiene una secuencia correspondiente de elementos de ''noticias'', que pueden diferir en longitud. En el ejemplo anterior, URL1 tiene 3 noticias correspondientes y URL3 tiene solo una.
A veces, una URL no tiene el elemento correspondiente "noticias":
y = [''URL4'',''news1'',''news2'',''URL5'',''URL6'',''news1'']
Puedo encontrar fácilmente cada índice de URL y los elementos de "noticias" de cada URL.
Mi pregunta es: ¿es posible transformar esta lista en un diccionario en el que el elemento URL es la clave y los elementos "noticias" son un valor de lista / tupla?
Rendimiento esperado
z = {''URL1'':(''news1'', ''news2'', ''news3''),
''URL2'':(''news1'', ''news2''),
''URL3'':(''news1''),
''URL4'':(''news1'', ''news2''),
''URL5'':(),
''URL6'':(''news1'')}
He visto una pregunta similar en esta post , pero no resuelve mi problema.
Otra solución usando
groupby
, one-liner:
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)
Huellas dactilares:
{''URL1'': (''news1'', ''news2'', ''news3''),
''URL2'': (''news1'', ''news2''),
''URL3'': (''news1'',),
''URL4'': (''news1'', ''news2''),
''URL5'': (),
''URL6'': (''news1'',)}
Puede usar
itertools.groupby
con una función
key
para identificar una 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)]])
Salida:
{
''URL1'': (''news1'', ''news2'', ''news3''),
''URL2'': (''news1'', ''news2''),
''URL3'': (''news1'',),
''URL4'': (''news1'', ''news2''),
''URL5'': (),
''URL6'': (''news1'',)
}
Puedes hacerlo así:
>>> 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'',)}
Simplemente puede usar los índices de las claves de URL en la lista y tomar lo que hay entre los índices y asignarlos al primer
Me gusta esto:
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)
salida:
{''URL1'': [''news1'', ''news2'', ''news3''], ''URL2'': [''news1'', ''news2''], ''URL3'': [''news1'']}