【问题标题】:intersection of two lists of dictionaries by key/value pair按键/值对的两个字典列表的交集
【发布时间】:2015-10-25 03:26:37
【问题描述】:

我有两个格式的字典列表:

systolic_sex = [
        {'attribute': u'bp', 'value_d': 133.0, 'value_s': u'133', 'sid': 6}, 
        {'attribute': u'bp', 'value_d': 127.0, 'value_s': u'127', 'sid': 17}, 
        {'attribute': u'bp', 'value_d': 121.0, 'value_s': u'121', 'sid': 18}, 
        {'attribute': u'bp', 'value_d': 127.0, 'value_s': u'127', 'sid': 27}, 
        {'attribute': u'bp', 'value_d': 120.0, 'value_s': u'120', 'sid': 42},
        {'attribute': u'SEX', 'value_d': 0.0, 'value_s': u'M', 'sid': 6},      
        {'attribute': u'SEX', 'value_d': 0.0, 'value_s': u'M', 'sid': 17},   
        {'attribute': u'SEX', 'value_d': 0.0, 'value_s': u'M', 'sid': 18},
        {'attribute': u'SEX', 'value_d': 0.0, 'value_s': u'M', 'sid': 27},   
        {'attribute': u'SEX', 'value_d': 0.0, 'value_s': u'M', 'sid': 42}
    ]



sex = [
        {'attribute': u'SEX', 'value_d': 0.0, 'value_s': u'M', 'sid': 6},      
        {'attribute': u'SEX', 'value_d': 0.0, 'value_s': u'M', 'sid': 17},   
        {'attribute': u'SEX', 'value_d': 0.0, 'value_s': u'M', 'sid': 42}
    ]

我想通过键 'sid' 的值来匹配这些列表,这样如果两者中的 'sid' 值相同,我就有一个匹配项,否则我没有。如果我有一个匹配项,然后我将两个集合中的 'sid' 匹配的字典相应地附加到一个新列表中,如下所示

new_set = [
        {'attribute': u'bp', 'value_d': 133.0, 'value_s': u'133', 'sid': 6}, 
        {'attribute': u'SEX', 'value_d': 0.0, 'value_s': u'M', 'sid': 6},
        {'attribute': u'bp', 'value_d': 127.0, 'value_s': u'127', 'sid': 17}, 
        {'attribute': u'SEX', 'value_d': 0.0, 'value_s': u'M', 'sid': 17},
        {'attribute': u'bp', 'value_d': 120.0, 'value_s': u'120', 'sid': 42},
        {'attribute': u'SEX', 'value_d': 0.0, 'value_s': u'M', 'sid': 42}
    ]

我尝试了各种方法来将它们相交,包括修改来自 Match set of dictionaries 的答案,但我希望创建一个具有匹配 sid 的字典的新列表,而不是替换两个列表之间的值。

【问题讨论】:

  • 你能展示一下在这种情况下所需的输出应该是什么样子吗?听起来您实际上想加入sid“列”上的两个“表”?
  • LOL 出于某种原因,输出与我想象的完全不同。删除了我的答案。
  • 这是一个很好的数据重新映射!对未来的工作很有用。
  • 注意:设置的性别可以是 systolic_sex 的形式,也就是说,在 'sid' 键的单个值上具有多个不同的 'attribute' 键值集。例如,我可以有两个集合,systolic_sex 和 diastolic_sex,然后通过 'sid' 匹配所有键。抱歉,如果在原始帖子中不清楚。在任何情况下,@dawg 的解决方案都可以解决这个问题,尽管我没有明确说明这个要求。

标签: python dictionary intersection


【解决方案1】:

如果您经常处理此类数据,您可能会对使用pandas 感兴趣。你的字典已经是 pandas 喜欢的形式,所以你可以这样做:

import pandas

systolic_sex = pandas.DataFrame(systolic_sex)
sex = pandas.DataFrame(sex)

matches = systolic_sex[systolic_sex.sid.isin(sex.sid)]

如果您希望数据恢复为与您提供的格式相同的格式,您可以

output = matches.to_dict(orient='records')

【讨论】:

  • 我实际上使用 Pandas 来处理数据,如果我不能使用仅 python 的方法,我会这样做。实际上,我比我接受的解决方案更喜欢这个解决方案,因为它更简洁,减去了额外的导入。
  • 是的,我发现无论我走到哪里,Pandas 都变得非常标准,所以我认为更好地处理此类数据不会有太多开销。
  • 对于我必须做的事情,它有点复杂。我会再给它一次机会。
  • 将DataFrame转换回字典列表的最后一步是matches.T.to_dict().values() ...很好(你可能已经说服了我,特别是因为我有一个即将进行的项目,其中有很多类似的箍要跳过) !
  • 哦,我必须评论一下,你是我见过的罕见的编码员/数据人,实际上使用正确的主谓协议来处理数据! (数据是/数据是)
【解决方案2】:

在您链接的帖子中取消答案:

systolic_sex = dict((e['sid'], e) for e in systolic_sex)
sex = set(e['sid'] for e in sex)

matches = []
for sid,v in systolic_sex.items():
    if sid not in sex: continue
    matches.append(v)

【讨论】:

  • 我在编辑之前尝试过这个,它适用于所述问题。但是,我意识到我的第一组应该合并为 systolic_sex。我已经相应地编辑了原始帖子。
  • 得到了它,部分,但我知道去哪里用它。感谢您让我重回正轨,并教授一些新的 Python 技巧! (^_^)
【解决方案3】:
>>> uniq=set(e['sid'] for e in sex) 
>>> filter(lambda d: d['sid'] in uniq, systolic_sex)
[{'attribute': u'bp', 'sid': 6L, 'value_s': u'133', 'value_d': 133.0},        
 {'attribute': u'bp', 'sid': 17L, 'value_s': u'127', 'value_d': 127.0},  
 {'attribute': u'bp', 'sid': 42L, 'value_s': u'120', 'value_d': 120.0}, 
 {'attribute': u'SEX', 'sid': 6L, 'value_s': u'M', 'value_d': 0.0}, 
 {'attribute': u'SEX', 'sid': 17L, 'value_s': u'M', 'value_d': 0.0}, 
 {'attribute': u'SEX', 'sid': 42L, 'value_s': u'M', 'value_d': 0.0}]

【讨论】:

  • 这是列表理解既短又漂亮的情况之一:[d for d in systolic_sex if d['sid'] in uniq]
  • 我刚刚在两个比我在示例中给出的更通用的数据集上进行了测试(键“sid”的值有任意重复,但键上有两个以上的非重复值'属性',它按预期工作)。 pandas 解决方案很可能需要进行一些调整,因为它给出了与@inspectorG4dget 解决方案相同的结果,这需要针对更一般的情况进行一些调整。
  • 在一般情况下,pandas 是他最容易使用的建议。
【解决方案4】:

我最终使用了以下内容(根据@chtohnicdaemon):

import pandas
#-----> code snipped here
#----->
# iterate over record sets returned by SQLAlchemy to populate list
    for result in query_right:
        data = {'sid': result.patient_sid,
                'value_s': result.string_value,
                'value_d': result.double_value,
                'attribute': result.attribute_value}

                result_right.append(data)

    for result in left_child:
        data = {'sid': result.patient_sid,
                'value_s': result.string_value,
                'value_d': result.double_value,
                'attribute': result.attribute_value}

                result_left.append(data)

# convert list of dictionaries to data frames
right = pandas.DataFrame(right_result)
left = pandas.DataFrame(left_result)

# get matches
matches_right  = right[right.sid.isin(left.sid)]
matches_left  = left[left.sid.isin(right.sid)]

# combine matched sets into single set
frames = [matches_right,matches_left]

# concatenate data, drop duplicates and convert back to a list of dictionaries
result = pd.concat(frames).drop_duplicates().to_dict(orient='records')

工作就像一个魅力!

【讨论】:

  • drop_duplicates 无法就地工作,因此该行实际上在这里没有做任何事情。您也不需要在“获取匹配”区域中额外调用pandas.Dataframe。您可以对从“连接集”开始的所有部分执行pandas.concat(frames).drop_duplicates().to_dict(orient='records')
  • drop_duplicates 从 python 解释器工作(我还没有在我的代码中测试它)。除此之外,我猜额外的数据帧确实是多余的,否则我喜欢单行。马哈洛!
  • 你会看到结果,但它没有被存储。很少有 pandas 函数可以正常工作。
  • 我正在编辑上述内容以反映这些更改。我还为这个问题添加了更多背景信息。顺便说一句,这在我的代码中就像一个魅力。
  • 我看到你正在从数据库中读取数据。你可以直接用pandas.read_sql
猜你喜欢
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-02
  • 2012-04-12
相关资源
最近更新 更多