我有一个标记数组,每个标记对应一个从 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']
