【问题标题】:Find the pair of dictionary keys that have the most common values查找具有最常见值的一对字典键
【发布时间】:2023-01-05 20:30:12
【问题描述】:

我需要编写一个函数来查找具有最共同爱好的一对夫妇,即这对夫妇的共同爱好与不同爱好的比率应该最高。如果多对具有相同的最佳比率,则返回哪对并不重要,唯一的例外是当多对共享他们的所有爱好时,在这种情况下,将返回具有最多共享爱好的一对。

def find_two_people_with_most_common_hobbies(data: str) -> tuple:
    new_dict = create_dictionary(data) # creates a dictionary in the form {name1: [hobby1, hobby2, ...], name2: [...]}
    value_list = [] # list that stores all hobbies, duplicates included
    for value in new_dict.items():
        for ele in value[1]:
            value_list.append(ele)
    filtered_list = set([x for x in value_list if value_list.count(x) > 1]) # list where hobbies appear more than once, no duplicates
    return tuple([k for k, v in new_dict.items() if set(v).intersection(filtered_list)])

所以,给定输入"John:running\nJohn:walking\nMary:dancing\nMary:running\nNora:running\nNora:singing\nNora:dancing",输出应该是('Mary', 'Nora')。我的代码返回 ('John', 'Mary', 'Nora'),因为它会查找字典中的值与筛选列表中的值之间的交集。我不明白如何让它只返回共同的爱好。

【问题讨论】:

  • 如果您自己查看输入并尝试手动解决问题,您如何决定输出应该是 Mary 和 Nora?如何在代码中执行相同的步骤?您编写的代码似乎更像是一种询问“谁与其他人有共同爱好?”的解决方案。我们假设 create_dictionary 工作正常,因此您可能应该分享分配给 new_dict 的示例字典是什么,并将函数调用留在示例之外。
  • @Grismar 关于我的代码的作用,你是对的。它真的只适合那些有共同爱好的人。字典看起来像这样{'John': ['running', 'walking'], 'Mary': ['dancing', 'running'], 'Nora': ['running', 'singing', 'dancing' ]}
  • 一些旁注改进:1) 通过将 set(v).intersection(filtered_list) 替换为 not filtered_list.isdisjoint(v) 来获得短路和更高的效率(后者避免每次调用临时sets,并且可以在找到第一个重叠元素时立即停止处理,即使第一个测试元素存在重叠,交集也必须运行完成)。 2)写setcomps,不要setify listcomps:{x for x in value_list if value_list.count(x) > 1}。更好的是{x for x, cnt in collections.Counter(value_list).items() if cnt > 1}

标签: python python-3.x dictionary


【解决方案1】:

我会这样做:

  • 将字典值转换为集合
  • 得到人的所有组合
  • 计算每对人的intersection(共同爱好)和symmetric difference(不同爱好)
  • 根据共同爱好除以不同爱好找到最大值,使用共同爱好的数量来划分相等的值。请注意,由于两者可能没有不同的爱好,因此我们使用一个函数来计算排序值,以便我们可以捕获 ZeroDivisionError。
import itertools

dd = {'John': ['running', 'walking'], 'Mary': ['dancing', 'running'], 'Nora': ['running', 'singing', 'dancing' ]}

ss = { k : set(v) for k, v in dd.items() }
# {'John': {'walking', 'running'}, 'Mary': {'dancing', 'running'}, 'Nora': {'singing', 'running', 'dancing'}}

pp = [t for t in itertools.combinations(dd.keys(), 2)]
# [('John', 'Mary'), ('John', 'Nora'), ('Mary', 'Nora')]

hh = { (p1, p2) : (len(ss[p1] & ss[p2]), len(ss[p1] ^ ss[p2])) for p1, p2 in pp }
# {('John', 'Mary'): (1, 2), ('John', 'Nora'): (1, 3), ('Mary', 'Nora'): (2, 1)}

def most_shared(key):
    try:
        ratio = hh[key][0] / hh[key][1]
    except ZeroDivisionError:
        ratio = float('inf')
    return (ratio, hh[key][0])

res = max(hh, key=most_shared)
# ('Mary', 'Nora')

【讨论】:

  • 非常感谢,非常有用。为了使您的代码更有意义,我想可以添加 if dd.keys() is None or len(dd.keys()) < 2: return None。那么如果输入的人少于两个,该函数将简单地返回 None。好吧,在我的情况下会,因为我有一个功能。
  • @QLimbo 是的 - 我没有考虑带有 0 或 1 个条目的 dict 的微不足道的情况,但你的建议是有道理的。有趣的问题!
  • @QLimbo 请注意,您可以只使用 len(dd) < 2,因为当作为变量引用时,字典默认为其键。
【解决方案2】:
s = "John:running
John:walking
Mary:dancing
Mary:running
Nora:running
Nora:singing
Nora:dancing"
d={}
for v in s.split('
'):
     k,v=v.split(':')
     if k in d:
          d[k].append(v)
     else:
          d[k]=[v]

for k1,v1 in d.items():
     for k2,v2 in d.items():
          if k1!=k2:
               for v in v1:
                    if v not in v2:
                         break
               else:
                    print(k1,k2)
           

【讨论】:

    【解决方案3】:

    我也被困在这个问题上,islam abdelmoumen 的回答有效,但我收到这些错误不知道为什么:(

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-06
      • 2012-12-08
      • 1970-01-01
      相关资源
      最近更新 更多