按照元素的特定顺序对列表进行排序

Sorting a list following specific order of elements

假设我需要像这样对列表进行排序:

A=[1,1,1,1,1,1,1,0,0,0]

按照4:1的1和0的比值,得到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 的长度。

提前致谢!

使用简单的算术

假设序列只包含零和一。

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

使用来自the itertools documentation的食谱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]

假设序列保证是 1 和 0 的列表

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]

这是一种无需集合或 itertools 的方法,假设只有零和一,并且您首先需要一个,然后是零:

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