Python 检查字典列表值中的值是否唯一

Python 检查字典列表值中的值是否唯一,python,dictionary,Python,Dictionary,我有两本字典: mems = {'member2': ['PCP1', 'PCP2'], 'member6': ['PCP1', 'PCP5'], 'member7': ['PCP2', 'PCP4', 'PCP5'], 'member9': ['PCP1', 'PCP5']} provs = {'PCP1': 2, 'PCP2': 1, 'PCP4': 1, 'PCP5': 1} 如何检查这些列表值中的项目是否唯一,并且不出现在字典中的任何其他位置?如果是唯一的,则将“成员”

我有两本字典:

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的PCP,然后添加到匹配项中,但它给出了错误的成员“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'}

为什么我这样做的时候诚信没有得到维护。更重要的是,有更好的方法吗?

如果先创建一个集合来查看它是否存在,然后查找它所属的成员,那么启动它可能会更容易

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. 

一种方法是更改代码的第二部分。一旦有了计数,就可以对原始值进行迭代,检查哪个值是唯一的

>>> 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'}

您仍然可以在此处使用计数器,只需将其转换为仅由单个发生的PROV过滤的集合,然后使用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)
首先,您可以反转mems:

现在很容易计算匹配项:在lenmems上过滤dict并再次反转:

matches = {mems[0]: pcp for pcp, mems in d1.items() if len(mems) == 1}
# {'member7': 'PCP4'}
您可以创建不包含匹配pcp的新的\u mems dict:

然后使用计数器更新provs:


不清楚你想做什么。酷!,你怎么能让结果不是一个列表,只是{'member7':'PCP4'}我把它做成了一个列表,以防有可能多个元素对一个键是独占的。如果您只想要一个,只需使用p.pop而不是listpworks!只需弹出与新版本匹配的成员,但“PCP4”仍在新版本中显示,但计数为0。@BenSmith。未测试,但最后一行的del new_provs[pcp]应该可以完成。很好,那么在计数时如何从ms中删除成员和provs中删除提供者
mems = {'member2': ['PCP1', 'PCP2'],
  'member6': ['PCP1', 'PCP5'],
  'member7': ['PCP2', 'PCP4', 'PCP5'],
  'member9': ['PCP1', 'PCP5']}

provs = {'PCP1': 2, 'PCP2': 1, 'PCP4': 1, 'PCP5': 1}
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 = {mems[0]: pcp for pcp, mems in d1.items() if len(mems) == 1}
# {'member7': 'PCP4'}
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']}
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})