结合共享值和键的python词典

时间:2018-03-16 15:28:01

标签: python dictionary

我正在根据字符串编辑距离进行一些实体匹配,我的结果是一个带有键(查询字符串)的字典和基于某些评分标准的值[类似字符串列表]。

例如:

results = {
  'ben' : ['benj', 'benjamin', 'benyamin'],
  'benj': ['ben', 'beny', 'benjamin'],
  'benjamin': ['benyamin'],
  'benyamin': ['benjamin'],
  'carl': ['karl'],
  'karl': ['carl'],
}

每个值还有一个相应的字典项,它是关键字(例如' carl'' karl')。

我需要组合具有共享值的元素。选择一个值作为新键(假设最长的字符串)。在上面的例子中,我希望得到:

results = {
  'benjamin': ['ben', 'benj', 'benyamin', 'beny', 'benjamin', 'benyamin'],
  'carl': ['carl','karl']
}

我已经尝试使用键遍历字典,但我不能围绕如何迭代和比较每个字典项及其值列表(或单个值)。

2 个答案:

答案 0 :(得分:3)

这是一个使用collections.defaultdict并设置的解决方案。

所需的输出与您拥有的输出非常相似,并且可以轻松操作以对齐。

from collections import defaultdict

results = {
  'ben' : ['benj', 'benjamin', 'benyamin'],
  'benj': ['ben', 'beny', 'benjamin'],
  'benjamin': 'benyamin',
  'benyamin': 'benjamin',
  'carl': 'karl',
  'karl': 'carl',
}

d = defaultdict(set)

for i, (k, v) in enumerate(results.items()):
    w = {k} | (set(v) if isinstance(v, list) else {v})
    for m, n in d.items():
        if not n.isdisjoint(w):
            d[m].update(w)
            break
    else:
        d[i] = w

result = {max(v, key=len): v for k, v in d.items()}

# {'benjamin': {'ben', 'benj', 'benjamin', 'beny', 'benyamin'},
#  'carl': {'carl', 'karl'}}

感谢@IMCoins在第二次循环中操纵vw的想法。

<强>解释

主要有三个步骤:

  1. 将值转换为一致的设置格式,包括原始字典中的键和值。
  2. 循环浏览此词典并将值添加到新词典中。如果有某个键的交叉点[即集合不是不相交的],然后使用该密钥。否则,添加到通过枚举确定的新密钥。
  3. 通过将最大长度键映射到值来在最终转换中创建结果字典。

答案 1 :(得分:2)

编辑:虽然表演不是问题所在,但我冒昧地在jpp的答案之间进行了一些测试,我的......这是完整的剧本。我的脚本在17.79秒内执行测试,在23.5秒内执行测试。

import timeit

results = {
  'ben' : ['benj', 'benjamin', 'benyamin'],
  'benj': ['ben', 'beny', 'benjamin'],
  'benjamin': ['benyamin'],
  'benyamin': ['benjamin'],
  'carl': ['karl'],
  'karl': ['carl'],
}

def imcoins(result):
    new_dict = {}
    # .items() for python3x
    for k, v in results.iteritems():
        flag = False
        #   Checking if key exists...
        if k not in new_dict.keys():
            #   But then, we also need to check its values.
            for item in v:
                if item in new_dict.keys():
                    #   If we update, set the flag to True, so we don't create a new value.
                    new_dict[item].update(v)
                    flag = True
            if flag == False:
                new_dict[k] = set(v)

    #   Now, to sort our newly created dict...
    sorted_dict = {}
    for k, v in new_dict.iteritems():
        max_string = max(v)
        if len(max_string) > len(k):
            sorted_dict[max(v, key=len)] = set(v)
        else:
            sorted_dict[k] =  v

    return sorted_dict

def jpp(result):
    from collections import defaultdict

    res = {i: {k} | (set(v) if isinstance(v, list) else {v}) \
          for i, (k, v) in enumerate(results.items())}

    d = defaultdict(set)

    for i, (k, v) in enumerate(res.items()):
        for m, n in d.items():
            if n & v:
                d[m].update(v)
                break
        else:
            d[i] = v

    result = {max(v, key=len): v for k, v in d.items()}
    return result

iterations = 1000000
time1 = timeit.timeit(stmt='imcoins(results)', setup='from __main__ import imcoins, results', number=iterations)
time2 = timeit.timeit(stmt='jpp(results)', setup='from __main__ import jpp, results', number=iterations)

print time1 # Outputs : 17.7903265883
print time2 # Outputs : 23.5605850732

如果我将导入从他的函数移动到全局范围,它会给出...

imcoins:13.4129249463秒

jpp:21.8191823393秒

相关问题