Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Sorting a list of objects on 4 attributes, and then on random

I have the following problem. I want to solve a list with objects on 4 separate attributes, e.g. first it is sorted in descending order on attribute a, then on b, then attribute c and then attribute d. I do this like this:

list = sorted(list, key=lambda x : (x.a, x.b, x.c, x.d), reverse=True)

But in case all attributes are still equal, I want to break the tie by determining their order at random. E.g. in an example problem:

1: a=3 b=2 c=3 d=1
2: a=3 b=2 c=3 d=1
3: a=3 b=2 c=3 d=1
4: a=1 b=3 c=4 d=5
5: a=1 b=3 c=4 d=5
6: a=0 b=1 c=1 d=1
7: a=0 b=1 c=1 d=1

I want the order of object 1, 2, and 3 to be determined randomly. Also the order of object 6 and 7 needs to be determined randomly. So object 1, 2 and 3 have 33% chance to come in one of the first three positions. Object 6 and 7 have a 50% chance to come in the sixth or seventh position.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

If there are only ties between two objects this is easily solved:

list = sorted(list, key=lambda x : (x.a, x.b, x.c, x.d, random.random()<0.5), reverse=True)

But what if 3 or more objects are tied? How would I make sure for instance that 3 equal objects have 33% to be first in their ordering.

I have been wondering this for a while now and I am curious if anyone has suggestions to efficiently solve this problem.

>Solution :

You would simply do this:

list = sorted(list, key=lambda x : (x.a, x.b, x.c, x.d, random.random()), reverse=True)

Since random.random() will generate a floating point number between 0 and 1, the odds of two records actually getting the same value here is vanishingly small. Elements that have the same attributes otherwise will get sorted by these random values.

If you insist on perfect randomness, you shouldn’t use random to begin with, but something like this in a better random library would work:

options = list(range(len(xs)))
random.shuffle(options)
list = sorted(xs, key=lambda x : (x.a, x.b, x.c, x.d, options.pop(), reverse=True)

This works because the options are now guaranteed to be unique and assuming the random library does a perfect job of fairly shuffling the options, you will always get different values with an equal chance for all records.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading