for dict python file dictionary

for - dict() python



Crear dict de la lista de la lista (7)

Tengo un archivo de texto que leí. Este es un archivo de registro por lo que sigue un patrón particular. Necesito crear un JSON en última instancia, pero a partir de la investigación de este problema, una vez que esté en un dictado, se tratará de usar json.loads() o json.dumps() .

Una muestra del archivo de texto está abajo.

INFO:20180606_141527:submit:is_test=False INFO:20180606_141527:submit:username=Mary INFO:20180606_141527:env:sys.platform=linux2 INFO:20180606_141527:env:os.name=ubuntu

La estructura de dictado que estoy buscando últimamente es

{ "INFO": { "submit": { "is_test": false, "username": "Mary" }, "env": { "sys.platform": "linux2", "os.name": "ubuntu" } } }

Estoy ignorando la información de marca de tiempo en cada lista por ahora.

Este es un fragmento del código que estoy usando,

import csv tree_dict = {} with open(''file.log'') as file: for row in file: for key in reversed(row.split(":")): tree_dict = {key: tree_dict}

Lo que resulta en una salida no deseada,

{''INFO'': {''20180606_141527'': {''submit'': {''os.name=posix/n'': {''INFO'': {''20180606_141527'': {''submit'': {''sys.platform=linux2/n'': {''INFO'': {''20180606_141527'': {''submit'': {''username=a227874/n'': {''INFO'': {''20180606_141527'': {''submit'': {''is_test=False/n'': {}}}}}}}}}}}}}}}}}

Necesito rellenar dinámicamente el dict porque no conozco los nombres reales de campo / clave.


Compruebe la presencia de llaves:

import csv import json tree_dict = {} with open(''file.log'') as file: tree_dict = {} for row in file: keys = row.split(":") if keys[0] not in tree_dict: tree_dict[keys[0]] = {} if keys[-2] not in tree_dict[keys[0]]: tree_dict[keys[0]][keys[-2]] = {} key, value = keys[-1].split("=") if value == "False": value = False if value == "True": value = True tree_dict[keys[0]][keys[-2]][key] = value dumped = json.dumps(tree_dict)


Este es uno de los casos raros donde la recursión en Python parece ser apropiada y útil. La siguiente función agrega un value al diccionario jerárquico d especificado por la lista de keys :

def add_to_dict(d, keys, value): if len(keys) == 1: # The last key d[keys[0]] = value return if keys[0] not in d: d[keys[0]] = {} # Create a new subdict add_to_dict(d[keys[0]], keys[1:], value)

La función trabaja con los diccionarios de profundidad arbitraria. El resto es solo cuestión de llamar a la función:

d = {} for line in file: keys, value = line.split("=") keys = keys.split(":") add_to_dict(d, keys, value.strip())

Resultado:

{''INFO'': {''20180606_141527'': { ''submit'': {''is_test'': ''False'', ''username'': ''Mary''}, ''env'': {''sys.platform'': ''linux2'', ''os.name'': ''ubuntu''}}}}

Puede modificar el código para excluir ciertos niveles (como la marca de tiempo).


Fuente :

import os with open(''file.log'') as file: tree_dict = {} is_test = False username = "" sysplatform = "" osname = "" for row in file: row = row.rstrip(''/n'') for key in reversed(row.split(":")): if not key.find(''is_test''): is_test = key.split(''='')[1] elif not key.find(''username''): username =key.split(''='')[1] elif not key.find(''sys.platform''): sysplatform = key.split(''='')[1] elif not key.find(''os.name''): osname = key.split(''='')[1] tree_dict = { "INFO": { "submit": { "is_test": is_test, "username": username }, "env": { "sys.platform": sysplatform, "os.name": osname } } } print(tree_dict)

Resultado:

{''INFO'': {''submit'': {''is_test'': ''False'', ''username'': ''Mary''}, ''env'': {''sys.platform'': ''linux2'', ''os.name'': ''ubuntu''}}}


Puedes usar itertools.groupby :

import itertools, re content = [re.split(''/=|:'', i.strip(''/n'')) for i in open(''filename.txt'')] new_content = [[a, *c] for a, _, *c in content] def group_vals(d): new_d = [[a, [c for _, *c in b]] for a, b in itertools.groupby(sorted(d, key=lambda x:x[0]), key=lambda x:x[0])] return {a:b[0][0] if len(b) ==1 else group_vals(b) for a, b in new_d}

import json print(json.dumps(group_vals(new_content), indent=4))

Salida:

{ "INFO": { "env": { "os.name": "ubuntu", "sys.platform": "linux2" }, "submit": { "is_test": "False", "username": "Mary" } } }


Puedes usar una collections.defaultdict() anidada.defaultdict collections.defaultdict() aquí:

from collections import defaultdict from pprint import pprint d = defaultdict(lambda: defaultdict(dict)) with open(''sample.txt'') as in_file: for line in in_file: info, _, category, pair = line.strip().split('':'') props, value = pair.split(''='') d[info][category][props] = value pprint(d)

Lo que da lo siguiente:

defaultdict(<function <lambda> at 0x7ff8a341aea0>, {''INFO'': defaultdict(<class ''dict''>, {''env'': {''os.name'': ''ubuntu'', ''sys.platform'': ''linux2''}, ''submit'': {''is_test'': ''False'', ''username'': ''Mary''}})})

Nota: defaultdict() es una subclase del dictado incorporado, por lo que no es motivo para convertirlo en dict en el resultado final. Además, defaultdict() también se puede serializar a JSON con json.dumps() .


import re from functools import reduce with open(''file.txt'') as f: lines = f.readlines() def rec_merge(d1, d2): for k, v in d1.items(): if k in d2: d2[k] = rec_merge(v, d2[k]) d3 = d1.copy() d3.update(d2) return d3 lst_of_tup = re.findall(r''^([^:]*):[/d_]+:([^:]*):([^=]*)=(.*)$'', lines, re.MULTILINE) lst_of_dct = [reduce(lambda x,y: {y:x}, reversed(t)) for t in lst_of_tup] dct = reduce(rec_merge, lst_of_dct) pprint(dct) # {''INFO'': {''env'': {''os.name'': ''ubuntu'', ''sys.platform'': ''linux2''}, # ''submit'': {''is_test'': ''False'', ''username'': ''Mary''}}}


with open(''demo.txt'') as f: lines = f.readlines() dct = {} for line in lines: # param1 == INFO # param2 == submit or env # params3 == is_test=False etc. param1, _, param2, params3 = line.strip().split('':'') # create dct[param1] = {} if it is not created dct.setdefault(param1, {}) # create dct[param1][param2] = {} if it is no created dct[param1].setdefault(param2, {}) # for example params3 == is_test=False # split it by ''='' and now we unpack it # k == is_test # v == False k, v = params3.split(''='') # and update our `dict` with the new values dct[param1][param2].update({k: v}) print(dct)

Salida

{ ''INFO'': { ''submit'': { ''is_test'': ''False'', ''username'': ''Mary'' }, ''env'': { ''sys.platform'': ''linux2'', ''os.name'': ''ubuntu'' } } }