【问题标题】:Redistribute dictionary value lists重新分配字典值列表
【发布时间】:2018-10-24 17:06:09
【问题描述】:

我有以下字典:

groups = {"group 1": [1, 2, 3, 4],
          "group 2": [5, 6, 7, 8],
          "group 3": [9, 10, 11, 12],
          "group 4": [13, 14]}

当组的长度小于最小大小 (group_size=4) 时,我想将成员重新分配到其他组。在这种情况下,结果将类似于:

groups = {"group 1": [1, 2, 3, 4, 13],
          "group 2": [5, 6, 7, 8, 14],
          "group 3": [9, 10, 11, 12]}

我有以下代码,它有效,但效率低于我想要的:

# Identify small groups
small_groups = []
for group_name, group_members in groups.items():
    if len(group_members) < group_size:
        small_groups.append(group_name)

# Redistribute members of small groups to the larger groups
to_redistribute = []
for group_name in small_groups:
    to_redistribute.extend(groups.pop(group_name))

for group_name, group_members in groups.items():
    if not to_redistribute:
        break
    group_members.append(to_redistribute.pop())

重要提示:组的真正成员是字符串,而不是整数。

有没有更好的方法来重新分配字典值列表?

【问题讨论】:

  • 如果只有 5 个数字怎么办,我的意思是组大小小于 4 并且总值计数只有 5
  • 为什么效率低?
  • 抱歉,修复并编辑了我的答案。
  • 如果 minimum_size 与组数相比很大,您可以通过将要分发的值分组到块中来提高效率(例如一次发牌而不是发牌)一次)。但是,如果它的大小与您的示例相同,则更有可能减慢速度而不是加快速度。
  • @Kalyan - group_size 实际上是基于我将人们分成四分位数并从每四分位数 1 人组成的组。但是,因为我的人数不一定是 4 的倍数,所以并非所有组的人数都为 4。如果人数少于 4 人,则有其他逻辑可以处理。

标签: python python-3.x performance dictionary


【解决方案1】:

您的解决方案很好,但您可以使用itertools.cycle 将弹出和重新分配逻辑结合在一起。

from itertools import cycle

for k in list(groups.keys()):
    if len(groups[k]) < group_size:
        for v, k_ in zip(groups.pop(k), cycle(groups.keys())):
            groups[k_].append(v)

我们的想法是不断循环使用键以平均地重新分配数据。它在每次迭代中确定一个组是否超过阈值。如果一个组是有效的,那么以后增加它(通过重新分配)将永远使其低于阈值。但是,最初低于阈值的组(但在以后的迭代中直到稍后才达到)可能会在您从另一个已删除的组中增加值时变为有效。如果这没有发生,那么它将被删除,并且在未来的迭代中重新分配其数据。

请记住,最初计划删除的组现在可能在重新分配后变为有效,因此我们的解决方案在某些输入的输出上会有所不同。

print(groups)
{'group 1': [1, 2, 3, 4, 13],
 'group 2': [5, 6, 7, 8, 14],
 'group 3': [9, 10, 11, 12]}

【讨论】:

  • 感谢您的回答-我会仔细研究一下循环-但这并不能完全满足我的需求。如果所有组的大小不同,我需要将较小的组分配到较大的组中(我猜你的答案 b/c 中缺少 13 和 14)。有什么办法可以修改这种类型的解决方案吗?
  • @ZaxR 抱歉,缺少的 13 和 14 是错字,它可以正常工作。
  • @ZaxR 那么它的作用是动态确定一个组是否太小。如果一个组足够大,那么添加更多(通过重新分配)将永远不会使其太小。然而,最初太小的组在从另一个组增加值后可能会变得有效。如果没有,那么它将在未来的迭代中再次重新分发。
  • 知道了。感谢您的回答和解释!
【解决方案2】:
  1. 使用filtersum 拉出长度小于4 的串联列表
  2. 使用推导式重建具有长度大于或等于4 的列表的新字典
  3. 迭代地从过滤列表中删除一项并将其附加到新构建的字典键中,直到过滤列表中的所有项目都用完为止。

from itertools import cycle

f = lambda v: len(v) < 4
x = sum(filter(f, groups.values()), [])
g = {k: v for k, v in groups.items() if not f(v)}

c = cycle(g)
while x:
    g[next(c)].append(x.pop())

g

{'group 1': [1, 2, 3, 4, 14],
 'group 2': [5, 6, 7, 8, 13],
 'group 3': [9, 10, 11, 12]}

【讨论】:

    猜你喜欢
    • 2021-04-02
    • 2021-12-27
    • 2018-08-20
    • 2021-06-16
    • 1970-01-01
    • 2013-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多