按照特定顺序排序列表

3
假设我需要对以下列表进行排序:
A=[1,1,1,1,1,1,1,0,0,0]
按照1和0的比例为4:1进行排序,得到如下结果:
A=[1,1,1,1,0,1,1,1,0,0]
这是否可能呢? 我尝试使用以下方式进行计数:
count 命令:
scheme=[1,1,1,1,0,1,1,1,0,0]
       
for k, number in enumerate(scheme):
    visited.append(number)
    scheme[k] += visited.count(number)/len(scheme)

for z in scheme:
    new = sorted(scheme).index(z)
    final.append(sorted(que)[new])

但这并不是一种舒适的方法,因为scheme(指导列表)强烈依赖于初始列表 A 的长度。

提前感谢您!


2
列表中是否只包含1和0?为了澄清,顺序应该是4个1和0的运行,然后是剩余的1,最后是剩余的0 - 这正确吗? - BrokenBenchmark
1
你的样本输出如何满足比率要求? - Scott Hunter
请问您能否解释一下这个方案的逻辑?例如,使用more_itertools.interleave_evenlyA上返回[1, 1, 0, 1, 1, 0, 1, 1, 0, 1] - Stef
这似乎是一项人工练习 - 实际上或者给定的约束条件是什么?元素是否总是类似于值,即当它们相等时无法区分?列表是否总是预先排序的? - MisterMiyagi
2个回答

2

使用简单算术

假设该序列仅包含 0 和 1。

from collections import Counter

def reorder_4_1(seq):
    c = Counter(seq)
    q1, r1 = divmod(c[1], 4)
    diff = q1 - c[0]
    if diff > 0:
        return [1,1,1,1,0] * c[0] + [1] * (diff + r1)
    else:
        return [1,1,1,1,0] * q1 + [1] * r1 + [0] * (-diff)

print( reorder_4_1([1,1,1,1,1,1,1,0,0,0]) )
# [1, 1, 1, 1, 0, 1, 1, 1, 0, 0]

使用模块itertools

使用itertools文档中的roundrobin配方:

假设有两组元素要交错4:1

from itertools import cycle, islice

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    num_active = len(iterables)
    nexts = cycle(iter(it).__next__ for it in iterables)
    while num_active:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            # Remove the iterator we just exhausted from the cycle.
            num_active -= 1
            nexts = cycle(islice(nexts, num_active))

def interleave_4_1(a, b):
    a = iter(a)
    b = iter(b)
    return roundrobin(a, a, a, a, b)

print(list( interleave_4_1([1,1,1,1,1,1,1],[0,0,0]) ))
# [1, 1, 1, 1, 0, 1, 1, 1, 0, 0]

假设这个序列保证是由一串0和1组成的列表。
from collections import Counter
from itertools import repeat

# def roundrobin...

def reorder_4_1(seq):
    c = Counter(seq)
    a = repeat(1, c[1])
    b = repeat(0, c[0])
    return roundrobin(a, a, a, a, b)

print(list( reorder_4_1([1,1,1,1,1,1,1,0,0,0]) ))
# [1, 1, 1, 1, 0, 1, 1, 1, 0, 0]

这正是我所需要的(特别是算术解决方案),非常感谢! 如果我有一个二维列表,原始列表中的每个1和0都与一个字符串配对,会怎样呢? 例如:[(0,'罗马'),(1,'伦敦'),(1,'纽约'),...] 我对最后一个IF部分很好奇,特别是最终列表的RETURN,其中包含正确配对其名称的1和0,在这种不同情况下。 再次抱歉打扰! - and_36100
2
@AndreaCichellero 你可以通过执行 data = [(0, '罗马'), (1, '伦敦'), (1, '纽约'),...]; zeroes = [city for num, city in data if num == 0]; ones = [city for num, city in data if num == 1 然后使用 list(interleave_4_1(ones, zeroes)) 将城市分为两个列表。 - Stef

1

这里有一种方法,不需要使用集合或itertools,假设只有0和1,并且您想要先出现1,然后是0:

def ratio_sort(x,y,lst):

    counter_dict = {1:0,0:0}
    for num in lst:   # count the amount of ones and zeroes in lst
        counter_dict[num]+=1
    
    # find how many groups of ones and zeroes we have
    one_groups = counter_dict[1]//x 
    zero_groups = counter_dict[0]//y

    new_list = []
    for i in range(min(one_groups, zero_groups)):  # add ratios of ones and zeroes to new list
        new_list.extend(([1]*x)+([0]*y))
        counter_dict[1]-=x
        counter_dict[0]-=y

    new_list.extend(([1]*counter_dict[1])+([0]*counter_dict[0]))  # insert the leftovers
    return new_list

1
你的大循环 for i in range(min(one_groups, zero_groups)): 可以简单地被替换为 new_list = ([1] * x + [0] * y) * min(one_groups, zero_groups) - Stef
@Stef 如果我这样做,我还需要从每个字典条目中减去 x*min(one_groups, zero_groups)y*min(one_groups, zero_groups),是的,这种方式也非常有效,谢谢! - PurpleHacker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接