Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort a list based on a given distribution

Tags:

python

sorting

Answering one Question, I ended up with a problem that I believe was a circumlocution way of solving which could have been done in a better way, but I was clueless

There are two list

percent = [0.23, 0.27, 0.4, 0.1]
optimal_partition = [3, 2, 2, 1]

optimal_partition, is one of the integer partition of the number 8 into 4 parts

I would like to sort optimal_partition, in a manner which matches the percentage distribution to as closest as possible which would mean, the individual partition should match the percent magnitude as closest as possible

So 3 -> 0.4, 2 -> 0.27 and 0.23 and 1 -> 0.1

So the final result should be

[2, 2, 3, 1]

The way I ended up solving this was

>>> percent = [0.23, 0.27, 0.4, 0.1]
>>> optimal_partition = [3, 2, 2, 1]
>>> optimal_partition_percent = zip(sorted(optimal_partition),
                    sorted(enumerate(percent),
                       key = itemgetter(1)))
>>> optimal_partition = [e for e, _ in sorted(optimal_partition_percent,
                          key = lambda e: e[1][0])]
>>> optimal_partition
[2, 2, 3, 1]

Can you suggest an easier way to solve this?

By easier I mean, without the need to implement multiple sorting, and storing and later rearranging based on index.

Couple of more examples:

percent = [0.25, 0.25, 0.4, 0.1]
optimal_partition = [3, 2, 2, 1]
result = [2, 2, 3, 1]

percent = [0.2, 0.2, 0.4, 0.2]
optimal_partition = [3, 2, 2, 1]
result = [1, 2, 3, 2]
like image 312
Abhijit Avatar asked Feb 17 '26 08:02

Abhijit


1 Answers

from numpy import take,argsort

take(opt,argsort(argsort(perc)[::-1]))

or without imports:

zip(*sorted(zip(sorted(range(len(perc)), key=perc.__getitem__)[::-1],opt)))[1]

#Test

l=[([0.23, 0.27, 0.4, 0.1],[3, 2, 2, 1]),
   ([0.25, 0.25, 0.4, 0.1],[3, 2, 2, 1]),
   ([0.2,  0.2,  0.4, 0.2],[3, 2, 2, 1])]

def f1(perc,opt):
    return take(opt,argsort(argsort(perc)[::-1]))

def f2(perc,opt):
    return zip(*sorted(zip(sorted(range(len(perc)),
             key=perc.__getitem__)[::-1],opt)))[1]       

for i in l:
    perc, opt = i
    print f1(perc,opt), f2(perc,opt)

# output:
# [2 2 3 1] (2, 2, 3, 1)
# [2 2 3 1] (2, 2, 3, 1)
# [1 2 3 2] (1, 2, 3, 2)
like image 158
root Avatar answered Feb 19 '26 21:02

root



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!