Home > Software engineering >  Sorting a list following specific order of elements
Sorting a list following specific order of elements

Time:05-27

Let's say that I need to sort a list like:

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

following a ratio between 1 and 0 of 4:1, obtaining so A=[1,1,1,1,0,1,1,1,0,0].

Is that possible? I tried to use a count comand in this way:

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])

But this is not a comfortable approach since scheme, the guide list, depends strongly on initial list A lenght.

Thank you in advance!

CodePudding user response:

Using simple arithmetic

Assuming the sequence contains only zeroes and ones.

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]

Using module itertools

Using recipe roundrobin from the itertools documentation:

Assuming there are two groups of elements to interleave 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]

Assuming the sequence is guaranteed to be a list of ones and zeroes

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]

CodePudding user response:

Here is a way without collections or itertools, assuming only zeroes and ones and that you want ones first and then zeroes after:

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
  • Related