【问题标题】:checks if value in a dictionaries list values is unique检查字典列表值中的值是否唯一
【发布时间】:2020-02-05 04:58:57
【问题描述】:

我有两本词典:

mems = {'member2': ['PCP1', 'PCP2'],
  'member6': ['PCP1', 'PCP5'],
  'member7': ['PCP2', 'PCP4', 'PCP5'],
  'member9': ['PCP1', 'PCP5']}


provs = {'PCP1': 2, 'PCP2': 1, 'PCP4': 1, 'PCP5': 1}

如何检查这些列表值中的项目是否唯一并且没有出现在字典中的其他任何位置?如果它是唯一的,则将“成员”和“PCP”附加到名为matches = dict() 的新字典中,从'mems' 中删除该成员,然后将任何其他剩余的“PCP”添加到provs 中的计数中。哦,删除mems中唯一的那个

结果应该是这样的

mems = {'member2': ['PCP1', 'PCP2'],
'member6': ['PCP1', 'PCP5'],
'member7': ['PCP2', 'PCP4', 'PCP5'],
'member9': ['PCP1', 'PCP5']}

provs = {'PCP1': 2, 'PCP2': 2, 'PCP5': 2}

matches = ['member7' : 'PCP4'}

我不知道该怎么做。我尝试开始为mems 中的 PCP 创建一个计数器,并找到带有 1 的计数器,然后添加到 matches,但它给出了错误的成员“member9”。

pcpCounts = dict(collections.Counter(itertools.chain.from_iterable(new_members.values())))
print(pcpCounts)
{'PCP1': 3, 'PCP2': 2, 'PCP4': 1, 'PCP5': 2}

for (k,v), (k2,v2) in zip(memsCounter.items(), pcpCounter.items()):
if v2 == 1:
    match[k] = k2

print(matches)
{'member9': 'PCP4'}

当我这样做时,为什么不能保持完整性。更重要的是,有没有更好的方法呢?

【问题讨论】:

  • 不清楚你想做什么。

标签: python dictionary


【解决方案1】:

您仍然可以在此处使用计数器,只需将其转换为仅由单个出现的 provs 过滤的集合,然后使用 set.intersection 作为您的检查。

from collections import Counter

mems = {'member2': ['PCP1', 'PCP2'], 'member6': ['PCP1', 'PCP5'], 'member7': ['PCP2', 'PCP4', 'PCP5'], 'member9': ['PCP1', 'PCP5']}
provs = {'PCP1': 2, 'PCP2': 1, 'PCP4': 1, 'PCP5': 1}

#I'm using sum here instead of itertools.chain. It serves the same purpose
prov_counts = {p for p, c in Counter(sum(mems.values(), [])).items() if c == 1} 
prov_filter = map(prov_counts.intersection, mems.values())

matches = {m: list(p) for m, p in zip(mems, prov_filter) if p}

print(matches)

{'member7': ['PCP4']}

【讨论】:

  • 酷!,你怎么能让结果不是一个列表,只是{'member7': 'PCP4'}
  • 我把它列了一个列表,以防多个元素有机会独占一个键。如果您只想使用p.pop() 而不是list(p)
【解决方案2】:

首先,如果您创建一个集合以查看它是否存在,然后如果存在,则查找它所属的成员可能会更容易。

mems = {'member2': ['PCP1', 'PCP2'],
  'member6': ['PCP1', 'PCP5'],
  'member7': ['PCP2', 'PCP4', 'PCP5'],
  'member9': ['PCP1', 'PCP5']}

provs = {'PCP1': 2, 'PCP2': 1, 'PCP4': 1, 'PCP5': 1}

members = {}
x = set()
for k,v in mems.items():
    for i in v:
        x.add(i)
        try:
            members[i].append(k)
        except KeyError:
            members[i] = [k,]

print(x)
print(members)

for k in provs:
    if k in x:
        print('KEY: {0} in {1}'.format(k,members[k]))
        print('KEY: {0} in {1}'.format(k,len(members[k]))) # count the references. 

【讨论】:

    【解决方案3】:
    mems = {'member2': ['PCP1', 'PCP2'],
      'member6': ['PCP1', 'PCP5'],
      'member7': ['PCP2', 'PCP4', 'PCP5'],
      'member9': ['PCP1', 'PCP5']}
    
    provs = {'PCP1': 2, 'PCP2': 1, 'PCP4': 1, 'PCP5': 1}
    

    首先,你可以反转mems

    d1 = {}
    for mem, pcps in mems.items():
        for pcp in pcps:
            d1.setdefault(pcp, []).append(mem)
    
    # {'PCP1': ['member2', 'member6', 'member9'], 'PCP2': ['member2', 'member7'], 'PCP5': ['member6', 'member7', 'member9'], 'PCP4': ['member7']}
    

    现在计算matches 很容易:过滤len(mems) 上的字典并再次反转它:

    matches = {mems[0]: pcp for pcp, mems in d1.items() if len(mems) == 1}
    # {'member7': 'PCP4'}
    

    您可以创建一个不包含匹配的pcpnew_mems dict:

    new_mems = {mem: [pcp for pcp in pcps if pcp not in matches.values()] for mem, pcps in mems.items()}
    # {'member2': ['PCP1', 'PCP2'], 'member6': ['PCP1', 'PCP5'], 'member7': ['PCP2', 'PCP5'], 'member9': ['PCP1', 'PCP5']}
    

    然后使用计数器更新provs

    import collections
    new_provs = collections.Counter(provs)
    for mem, pcp in matches.items():
        new_provs.update(mems[mem]) # add 1 to each count
        new_provs[pcp] -= 2 # was 0 + 1 (line above) -> is 0
    
    # Counter({'PCP1': 2, 'PCP2': 2, 'PCP5': 2, 'PCP4': 0})
    

    【讨论】:

    • 有效!只需要从 new_mems 中弹出匹配的成员,而且,'PCP4' 仍然显示在 new_provs 中,但计数为 0。
    • @BenSmith。未经测试,但最后一行的del new_provs[pcp] 应该可以解决问题。
    【解决方案4】:

    这样做的一种方法是更改​​代码的第二部分。获得计数后,您可以遍历原始值,检查哪个值是唯一的。

    >>> mems = {'member2': ['PCP1', 'PCP2'],
    ... 'member6': ['PCP1', 'PCP5'],
    ... 'member7': ['PCP2', 'PCP4', 'PCP5'],
    ... 'member9': ['PCP1', 'PCP5']}
    >>> import collections, itertools
    >>> pcpCounts = collections.Counter(itertools.chain.from_iterable(mems.values()))
    >>> matches = {}
    >>> for k, pcps in mems.items():
    ...     for v in pcps:
    ...         if pcpCounts[v] == 1:
    ...             matches[k] = v
    ...
    >>> matches
    {'member7': 'PCP4'}
    

    【讨论】:

    • 很好,那么我将如何在计数时从 ms 中删除成员和从 provs 中删除提供者
    猜你喜欢
    • 2016-09-29
    • 1970-01-01
    • 1970-01-01
    • 2019-01-12
    • 2018-12-25
    • 2019-02-13
    • 1970-01-01
    • 2020-05-09
    • 1970-01-01
    相关资源
    最近更新 更多