Tengo dos listas de diccionarios. Tengo que comparar CodeDesc en trans y code_desc en code_tbl, y cuando haya una coincidencia, agregue el código de code_tbl a trans.

trans = [{'id': 12345, 'Name': 'John Smith', 'CodeDesc': 'XYZ'},
         {'id': 67891, 'Name': 'Jane Smith', 'CodeDesc': 'ABC'}]

code_tbl = [{'code': 98, 'code_desc': 'XYZ'},
            {'code': 76, 'code_desc': 'ABC'}]

Mi intención es tener algo como esto:

trans = [{'Id': 12345, 'Name': 'John Smith', 'CodeDesc': 'XYZ', 'Code': 98},
         {'Id': 67891, 'Name': 'Jane Smith', 'CodeDesc': 'ABC', 'Code': 76}]

Eventualmente, según las condiciones, los datos de trans deben escribirse en diferentes pestañas de un archivo de Excel.

Aquí está el código que tengo para esto, y aparece el error 'TypeError: los índices de cadena deben ser enteros'

for t in trans:
#print(t['CodeDesc'])
    for c in code_tbl:
        #print([c['code_desc'])
        if t['CodeDesc'] == c['code_desc']:
             trans.append(c['code'])

¿Qué estoy haciendo mal y cómo solucionarlo? Cuando imprimo t ['CodeDesc'] yc ['code_desc'] está imprimiendo todas las descripciones de código.

Cualquier ayuda sería muy apreciada. Soy nuevo en python. Usando XLSXWRITER para escribir el archivo de Excel.

2
TDL 10 sep. 2018 a las 03:48

4 respuestas

La mejor respuesta

Usted está agregando a la lista sobre la que está iterando cuando debería actualizar el diccionario correspondiente. Use dict.update en lugar de list.append:

if t['CodeDesc'] == c['code_desc']:
    t.update(Code=c['code'])
print (trans)
[{'Code': 98, 'CodeDesc': 'XYZ', 'Name': 'John Smith', 'id': 12345},
 {'Code': 76, 'CodeDesc': 'ABC', 'Name': 'Jane Smith', 'id': 67891}]

Alternativamente, puede generar un mapeo dict con una pasada y luego actualizar con otra pasada. Esta debería ser una solución lineal.

mapping = {c['code_desc'] : c['code'] for c in code_tbl}
for t in trans:
    t.update(Code=mapping.get(t['CodeDesc']))
print (trans)
[{'Code': 98, 'CodeDesc': 'XYZ', 'Name': 'John Smith', 'id': 12345},
 {'Code': 76, 'CodeDesc': 'ABC', 'Name': 'Jane Smith', 'id': 67891}]

Finalmente, si tienes pandas, te recomiendo hacer esto con un merge.

import pandas as pd
v = (pd.DataFrame(trans)
       .merge(pd.DataFrame(code_tbl), left_on='CodeDesc', right_on='code_desc') 
       .drop('code_desc', 1))
print (v.to_dict('r'))    
[{'CodeDesc': 'XYZ', 'Name': 'John Smith', 'id': 12345, 'code': 98}, 
 {'CodeDesc': 'ABC', 'Name': 'Jane Smith', 'id': 67891, 'code': 76}]
1
cs95 10 sep. 2018 a las 01:04

Para este caso particular, puede resolverlo usando una sintaxis lineal usando list comprehension:

output = [
    {
       'Id': elm.get('id'),
       'Name': elm.get('Name'),
       'CodeDesc': elm.get('CodeDesc'),
       'code': k.get('code')
    } for elm in trans for k in code_tbl if k.get('code_desc') == elm.get('CodeDesc')
]

print(output)

Salida:

[{'Id': 12345, 'Name': 'John Smith', 'CodeDesc': 'XYZ', 'code': 98},
 {'Id': 67891, 'Name': 'Jane Smith', 'CodeDesc': 'ABC', 'code': 76}]
0
Chiheb Nexus 10 sep. 2018 a las 01:20

Obtiene este error porque está modificando trans a medida que lo itera. Básicamente, está agregando c['code'] que es un int y luego su ciclo intentará ejecutarse en ese int.

0
Kirollos Morkos 10 sep. 2018 a las 00:56

Esto está funcionando perfecto para mí.

for i, (dict1, dict2) in enumerate(zip(trans, code_tbl)):
    if dict1['CodeDesc'] == dict2['code_desc']:
        trans[i].update({'code':dict2['code']})

La salida se imprime a continuación:

print(trans)

[{'id': 12345, 'Name': 'John Smith', 'CodeDesc': 'XYZ', 'code': 98},
 {'id': 67891, 'Name': 'Jane Smith', 'CodeDesc': 'ABC', 'code': 76}]
0
Khalil Al Hooti 10 sep. 2018 a las 02:12