Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将DB中的行数据合并到DICT列表中_Python_Python 3.x_Data Structures_Sqlite - Fatal编程技术网

Python 将DB中的行数据合并到DICT列表中

Python 将DB中的行数据合并到DICT列表中,python,python-3.x,data-structures,sqlite,Python,Python 3.x,Data Structures,Sqlite,我正在从SQLite的SELECT语句中读取数据。日期如下表所示: ID|Phone|Email|Status|Role 对于相同的ID、电话或电子邮件,可以返回多行。对于给定的行,Phone或Email可以为空/空。但是,对于相同的ID,Status的值始终相同,角色的值始终相同。例如: 1|1234567892|a@email.com| active |typeA 2|3434567893|b@email.com| active |typeB 2|3434567893|c@email.co

我正在从SQLite的
SELECT
语句中读取数据。日期如下表所示:

ID|Phone|Email|Status|Role
对于相同的
ID
电话
电子邮件
,可以返回多行。对于给定的行,
Phone
Email
可以为空/空。但是,对于相同的
ID
Status
的值始终相同,
角色的值始终相同。例如:

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
    。换句话说,相同
    ID
    的多行将被合并
  • 每个
    dict
    包含以下键:“id”、“电话”、“电子邮件”、“类型”、“角色”、“状态”
  • “电话”和“电子邮件”是列表,包含零个或多个项目,但没有重复项
  • “类型”也是一个列表,包含“电话”或“电子邮件”或两者,但没有重复项
  • 在最终列表中,
    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
as
list
中包含“电话”、“电子邮件”和“类型”,而不是
set
。原因是我需要将
合并后的
转储到JSON中,JSON不允许
设置

当遇到我通常使用的类似情况时:

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
是一个2d列表:

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\u info.values()

返回的,因此基本上你需要一种方法来查找一个ID,查看所有链接到它的电子邮件和电话号码,以及状态和滚动?@dermen,差不多,检查所有返回的行,将相关细节链接到每个ID。
结果
是一个2d列表吗?如果是这样,我有一个解决办法below@thanks我想知道答案。很高兴看到这里使用了
groupby
,我以前没有想到过。然而,有几个问题:1。通过使用
groupby
,您依赖于数据已经被排序(在本例中,通过
ID
字段)。这可能不适用于所有可能的输入,但可以通过返回按
ID
排序的选择结果的SQL查询来强制执行。2.您的解决方案中
ID\u info
的结构与我提出的不同,每个
dict
的每个字段现在都是一个列表,而我只需要将“email”和“phone”作为列表,而且每个
dict
都缺少“type”字段。需要添加两个小细节:在Python 3中,
xrange()
变成
range()
,和
map()
返回一个
map
对象,该对象不可下标,因此我们需要执行
list(list(map(set,zip(*g[1]))[i]
在您的示例中。@skyork,groupby应该可以工作,不管行的顺序如何,我刚刚用python2x测试了这个问题。我修复了上面的答案,用Python3x
map
range
工作。另外,还添加了类型条目。
groupby
只需遍历列表,只要键发生变化,它就会创建一个新的组。例如le,如果您移动行:
['2','3434567893','c@email.com“,”活动“,”类型B']
在输入的
ID
4和5行之间,属于
ID
2行的两行将不再分组在一起。所谓“类型”,我指的是单独的字段(类型
list
)在每个名为“类型”的
dict中,其值取决于是否有任何电子邮件和/或电话与给定的
ID
相关联。请参阅我问题中的要点4。明白了,那么我假设可以用python对结果进行排序,我会将此添加到中!感谢您建议使用
defaultdict
,我想知道“phone”和“e”“邮件”字段应声明为
set
,而不是
list
,因为多行上可能存在重复项,例如上面示例中的
ID
2行。