簡體   English   中英

將來自DB的行數據合並到字典列表中

[英]Consolidating row data from DB into a list of dicts

我正在從SQLite的SELECT語句讀取數據。 日期格式如下:

ID|Phone|Email|Status|Role

對於相同的IDPhoneEmail ,可能會返回多行。 對於給定的行,“ Phone或“ Email可以為空/ NULL。 但是,對於相同的IDStatus值始終相同, 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的數據,使得:

  • 最終列表的每一項都是一個dictresults每個唯一ID都是一個dict 換句話說,相同ID多行將被合並。
  • 每個dict包含以下鍵:“ id”,“電話”,“電子郵件”,“類型”,“角色”,“狀態”。
  • “電話”和“電子郵件”是列表,包含零個或多個項目,但沒有重復項。
  • “類型”也是一個列表,並且包含“電話”或“電子郵件”或兩者,但沒有重復項。
  • 順序dict進入決賽名單無所謂。

到目前為止,我已經提出了這一點:

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())

我想知道是否有更快和/或更簡潔的方法來做到這一點。

編輯:

最后一個細節:我希望有“手機”,“電子郵件”和“類型”中的每個dictlist ,而不是set 原因是我需要將consolidated轉儲到JSON,並且JSON不允許set

當遇到這樣的事情時,我通常使用:

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)

我假設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()返回

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM