Python 高效地添加到最短的桶中

Python 高效地添加到最短的桶中,python,Python,我试图将人们分成不同的群体,我希望能够始终在最空的群体中添加新的人 我有一本字典,里面有人,还有他们所在的组,还有一个新的人列表,可以“平均”添加到组中: groups = { 'alice': 'a', 'bob': 'b', 'charles': 'c', 'dawn': 'd', 'eric': 'a', 'frank': 'b', 'gina': 'd', 'henry': 'd' } people = ['ian', '

我试图将人们分成不同的群体,我希望能够始终在最空的群体中添加新的人

我有一本字典,里面有人,还有他们所在的组,还有一个新的人列表,可以“平均”添加到组中:

groups = {
    'alice': 'a',
    'bob': 'b',
    'charles': 'c',
    'dawn': 'd',
    'eric': 'a',
    'frank': 'b',
    'gina': 'd',
    'henry': 'd'
}

people = ['ian', 'jess', 'keith', 'lila', 'mike', 'nell', 'owen', 'patty']
我目前正在通过计算哪一组是最空的,添加分配给该组的下一个人,然后重新计算:

from collections import Counter
from operator import itemgetter

for person in people:
    counts = Counter(groups.values())
    print(counts)
    emptiest = min(counts.items(), key=itemgetter(1))
    groups[person] = emptiest[0]
    print(groups)

但是,每次重新计算最空的组有点低效。有人能提出更好的方法来实现这一点吗?

编辑-在群组中对现有人员进行寻址

如果组中有现有人员,则可以执行以下操作:

组={
“爱丽丝”:“a”,
“鲍勃”:“b”,
“查尔斯”:“c”,
“黎明”:d,
‘埃里克’:‘a’,
“弗兰克”:“b”,
“吉娜”:“d”,
“亨利”:“d”
}
#创建类似于{group:[人员列表]}的字典
groups_d={g:[]表示groups.values()中的g
对于分组中的p、g.items():
组d[g]。追加(p)
people=['ian','jess','keith','lila','mike','nell','owen','patty']
对于人中的p:
#获取类似于{人数:组}的字典
#注意:相同长度的组将被覆盖,
#但没关系
len_dict={len(pp):g代表g,pp在组中。\u d.items()}
#附加到具有最小长度的组
分组[len_dict[min(len_dict.keys())]]。追加(p)
同样,还有更多的“矢量化”方法,例如,您可以填充组,直到它们都相等,然后切换到下面建议的解决方案,这显然更快

先前的答案: 我认为效率低下的主要原因在于,您使用的格式是
{person:group}
,而不是
{group\u name:[person1,person2,…]}
。 这也有一个缺点,两个同名的人会打破逻辑

此外,一旦所有组的人数相同,您就可以简单地按顺序循环,无需重新计数

导入itertools
组=['a','b','c']
people=['alice','barbara','chris','diego','emanuel','florence']
组_d={g:[]表示组中的g}
组\循环=itertools.循环(组)
对于人中的p:
分组d[下一步(分组循环)]。追加(p)

>>组\u d
{'a':['alice','diego'],
“b”:[芭芭拉”,“伊曼纽尔],
'c':['克里斯','佛罗伦萨']}
然后,您可以通过简单的词典理解转换为所需的输出:

>>{p:g表示g,组中的人\u d.items()表示组中的人}
{'alice':'a',
“迭戈”:“a”,
“芭芭拉”:“b”,
“伊曼纽尔”:“b”,
‘克里斯’:‘c’,
“佛罗伦萨”:“c”}
为了说明显而易见的情况,最好的方法是简单地将您的人员列表转换为矩阵(例如,列数表示组数,行数表示每个组中的人数)。假设最终人数不均衡,则必须处理一些缺失的值,但这应该是微不足道的。
这类似于要求人们把自己放在
n
行中。

编辑-在组中对现有的人进行寻址

如果组中有现有人员,则可以执行以下操作:

组={
“爱丽丝”:“a”,
“鲍勃”:“b”,
“查尔斯”:“c”,
“黎明”:d,
‘埃里克’:‘a’,
“弗兰克”:“b”,
“吉娜”:“d”,
“亨利”:“d”
}
#创建类似于{group:[人员列表]}的字典
groups_d={g:[]表示groups.values()中的g
对于分组中的p、g.items():
组d[g]。追加(p)
people=['ian','jess','keith','lila','mike','nell','owen','patty']
对于人中的p:
#获取类似于{人数:组}的字典
#注意:相同长度的组将被覆盖,
#但没关系
len_dict={len(pp):g代表g,pp在组中。\u d.items()}
#附加到具有最小长度的组
分组[len_dict[min(len_dict.keys())]]。追加(p)
同样,还有更多的“矢量化”方法,例如,您可以填充组,直到它们都相等,然后切换到下面建议的解决方案,这显然更快

先前的答案: 我认为效率低下的主要原因在于,您使用的格式是
{person:group}
,而不是
{group\u name:[person1,person2,…]}
。 这也有一个缺点,两个同名的人会打破逻辑

此外,一旦所有组的人数相同,您就可以简单地按顺序循环,无需重新计数

导入itertools
组=['a','b','c']
people=['alice','barbara','chris','diego','emanuel','florence']
组_d={g:[]表示组中的g}
组\循环=itertools.循环(组)
对于人中的p:
分组d[下一步(分组循环)]。追加(p)

>>组\u d
{'a':['alice','diego'],
“b”:[芭芭拉”,“伊曼纽尔],
'c':['克里斯','佛罗伦萨']}
然后,您可以通过简单的词典理解转换为所需的输出:

>>{p:g表示g,组中的人\u d.items()表示组中的人}
{'alice':'a',
“迭戈”:“a”,
“芭芭拉”:“b”,
“伊曼纽尔”:“b”,
‘克里斯’:‘c’,
“佛罗伦萨”:“c”}
为了说明显而易见的情况,最好的方法是简单地将您的人员列表转换为矩阵(例如,列数表示组数,行数表示每个组中的人数)。假设最终人数不均衡,则必须处理一些缺失的值,但这应该是微不足道的。
这类似于要求人们将自己放在
n
行中。

通过将数据结构更改为
group\u name:[名称列表]
,您可以利用这样一个事实,即获取列表的长度很快,不需要迭代元素进行计数。因此,其运行/复杂度/效率为O(1)。所以您可以使用min来获得最短长度的列表,使用key,然后附加到该列表


{'a': ['alice', 'eric', 'jess', 'mike'], 'b': ['bob', 'frank', 'keith', 'nell'], 'c': ['charles', 'ian', 'lila', 'owen'], 'd': ['dawn', 'gina', 'henry', 'patty']}