我正在从SQLite的SELECT
语句中读取数据。日期的格式如下:
ID|Phone|Email|Status|Role
可能会为同一ID
,Phone
或Email
返回多行。对于给定的行,Phone
或Email
可以为空/ NULL。但是,对于相同的ID
,Status
的值始终相同,Role
的值相同。例如:
1|1234567892|a@email.com| active |typeA
2|3434567893|b@email.com| active |typeB
2|3434567893|c@email.com| active |typeB
3|5664567891|d@email.com|inactive|typeC
3|7942367891|d@email.com|inactive|typeC
4|5342234233| NULL | active |typeD
5| NULL |e@email.com| active |typeD
这些数据由Sqlite3
作为列表返回,我们称之为results
。我需要仔细检查它们并重新组织数据以在Python中构建另一个列表结构。最终列表基本上整合了每个ID
的数据,例如:
dict
,ID
中每个唯一results
一个。换句话说,将合并同一ID
的多个行。dict
都包含以下键:'id','phone','email','types','role','status'。dict
s的顺序不重要。到目前为止,我已经提出了这个问题:
processed = {}
for r in results:
if r['ID'] in processed:
p_data = processed[r['ID']]
if r['Phone']:
p_data['phones'].add(r['Phone'])
p_data['types'].add('phone')
if r['Email']:
p_data['emails'].add(r['Email'])
p_data['types'].add('email')
else:
p_data = {'id': r['ID'], 'status': r['Status'], 'role': r['Role']}
if r['Phone']:
p_data['phones'] = set([r['Phone']])
p_data.setdefault('types', set).add('phone')
if r['Email']:
p_data['emails'] = set([r['Email']])
p_data.setdefault('types', set).add('email')
processed[r['ID']] = p_data
consolidated = list(processed.values())
我想知道是否有更快速和/或更简洁的方法来做到这一点。
编辑:
最后一个细节:我希望将每个dict
中的“手机”,“电子邮件”和“类型”改为list
而不是set
。原因是我需要将consolidated
转储到JSON中,而JSON不允许set
。
答案 0 :(得分:1)
当面对这样的事情时,我通常会使用:
processed = collections.defaultdict(lambda:{'phone':set(),'email':set(),'status':None,'type':set()})
然后像:
for r in results:
for field in ['Phone','Email']:
if r[field]:
processed[r['ID']][field.lower()].add(r[field])
processed[r['ID']]['type'].add(field.lower())
最后,您可以将其转储到字典或列表中:
a_list = processed.items()
a_dict = dict(a_list)
关于集合的JSON问题,您可以在序列化或编写自定义编码器之前将集合转换为列表(非常有用!)。下面是一个扩展到处理集的日期的示例:
class JSONDateTimeEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime.datetime):
return int(time.mktime(obj.timetuple()))
elif isinstance(ojb, set):
return list(obj)
try:
return json.JSONEncoder.default(self, obj)
except:
return str(obj)
并使用它:
json.dumps(a_list,sort_keys=True, indent=2, cls =JSONDateTimeEncoder)
答案 1 :(得分:1)
我认为results
是一个二维列表:
print results
#[['1', '1234567892', 'a@email.com', ' active ', 'typeA'],
#['2', '3434567893', 'b@email.com', ' active ', 'typeB'],
#['2', '3434567893', 'c@email.com', ' active ', 'typeB'],
#['3', '5664567891', 'd@email.com', 'inactive', 'typeC'],
#['3', '7942367891', 'd@email.com', 'inactive', 'typeC'],
#['4', '5342234233', ' NULL ', ' active ', 'typeD'],
#['5', ' NULL ', 'e@email.com', ' active ', 'typeD']]
现在我们按ID分组此列表:
from itertools import groupby
data_grouped = [ (k,list(v)) for k,v in groupby( sorted(results, key=lambda x:x[0]) , lambda x : x[0] )]
# make list of column names (should correspond to results). These will be dict keys
names = [ 'id', 'phone','email', 'status', 'roll' ]
ID_info = { g[0]: {names[i]: list(list( map( set, zip(*g[1] )))[i]) for i in range( len(names))} for g in data_grouped }
现在的类型:
for k in ID_info:
email = [ i for i in ID_info[k]['email'] if i.strip() != 'NULL' and i != '']
phone = [ i for i in ID_info[k]['phone'] if i.strip() != 'NULL' and i != '']
if email and phone:
ID_info[k]['types'] = [ 'phone', 'email' ]
elif email and not phone:
ID_info[k]['types'] = ['email']
elif phone and not email:
ID_info[k]['types'] = ['phone']
else:
ID_info[k]['types'] = []
# project
ID_info[k]['id'] = ID_info[k]['id'][0]
ID_info[k]['roll'] = ID_info[k]['roll'][0]
ID_info[k]['status'] = ID_info[k]['status'][0]
ID_info.values()