Skip to main content
 首页 » 编程设计

列表/numpy数组中的Python平衡项

2025年05月04日17qq号

我有一个标记数组,每个标记对应一个从 1 到 n 的不同类。我需要平衡 tokens 数组/列表,以便每个类都有相同数量的标记。我想通过删除 tokens 的元素来做到这一点。

在下面的示例中,标记数量最少的类是 class 2,它只有 2 个标记。所以我想从其他类中删除元素,直到它们的计数也为 2。

例如

tokens  = array(['a','b','c','d','e','f','g','h','l']) 
 
classes = array([ 1 , 1 , 1 , 1 , 2 , 2 , 3 , 3 , 3]) 

在这个例子中,类是按升序排列的(为了任务的清晰度),但实际上,类没有特定的顺序。

例如

sol = array(['c','d','e','f','g','h']) 

或

sol = array(['a','b','e','f','g','h']) 

等等

显然,因为您可以选择要在多余类中删除的元素,所以您可以有不同的解决方案(如上)。我需要一个可以获取 tokens 和 classes 并输出 sol 的函数。

请您参考如下方法:

带有计数器的解决方案:

tokens = ['a','b','c','d','e','f','g','h','l'] 
lst    = [ 1 , 1 , 1 , 1 , 2 , 2 , 3 , 3 , 3] 
 
from collections import Counter 
 
c = Counter(lst) 
min_cnt = min(c.values()) 
new_lst = list( zip(tokens, lst) ) 
 
while True: 
    tmp = [] 
    should_break = True 
    for t, i in new_lst: 
        if c[i] > min_cnt: 
            c[i] -= 1 
            should_break = False 
        else: 
            tmp.append( (t, i) ) 
 
    new_lst = tmp 
 
    if should_break: 
        break 
 
print([t for t, _ in new_lst]) 

打印:

['c', 'd', 'e', 'f', 'h', 'l'] 

groupby 的其他可能解决方案:

tokens = ['a','b','c','d','e','f','g','h','l'] 
lst    = [ 1 , 1 , 1 , 1 , 2 , 2 , 3 , 3 , 3] 
 
from collections import Counter 
from itertools import groupby, islice 
 
c = Counter(lst) 
min_cnt = min(c.values()) 
 
out = [] 
for v, g in groupby(sorted(enumerate(zip(tokens, lst)), key=lambda k: k[1][1]), lambda k: k[1][1]): 
    out.extend(islice(g, 0, min_cnt)) 
 
print( [val for _, (val, _) in sorted(out, key=lambda k: k[0])] ) 

打印:

['a', 'b', 'e', 'f', 'g', 'h']