Home > Software design >  Sort a list of integers on absolute values with higher precedence positive number
Sort a list of integers on absolute values with higher precedence positive number

Time:06-03

How do I sort a list of integers based on their absolute values such that the positive number gets a higher precedence -

Sample Input

lst = [1, -3, 3, -3, 12, 10]

Expected Output

[1, 3, -3, -3, 10, 12]

I am able to do it right now with a code like this, but I am bothered by that arbitrary 0.1 in the function and wonder if there is a cleaner way

My code

sorted(lst, key=lambda x: abs(x) if x >= 0 else abs(x)   0.1)
# [1, 3, -3, -3, 10, 12]

CodePudding user response:

Another solution is having a tuple as a sorting key:

sorted(lst, key=lambda x: (abs(x), x < 0))

To understand it better:

 1 ~ (1, False)  ~ (1, 0)
-3 ~ (3, True)   ~ (3, 1)
 3 ~ (3, False)  ~ (3, 0)
-3 ~ (3, True)   ~ (3, 1)
12 ~ (12, False) ~ (12, 0)
10 ~ (10, False) ~ (10, 0)

CodePudding user response:

Create a custom comparator function which returns a tuple of size 2. The first value of the tuple is for absolute value and the second value is for ordering negative and positive values with the same absolute value.

sorted(lst, key=lambda x: (abs(x), -x))
# [1, 3, -3, -3, 10, 12]

For each value in the list values compared would be:

1  -> (1, -1)
3  -> (3, -3)
-3 -> (3,  3)
10 -> (10, -10)
12 -> (12, -12)

This way positive values are pushed to the beginning and negatives values to the end in each group.

CodePudding user response:

I'm quite confident that two simple sorts will be more efficient here than one more complex sort.

lst.sort(reverse=True)
lst.sort(key=abs)

Btw yours would be a bit shorter and faster (90 ms and 210 us in my benchmarks) without the unnecessary abs (you already know the sign):

sorted(lst, key=lambda x: x if x >= 0 else 0.5 - x)

Benchmark results with 100,000 random integers from -100,000 to 100,000 (Try it online!):

True   95 ms  original
True   42 ms  Kelly
True  128 ms  Yevhen
True  133 ms  Ch3ster

True   95 ms  original
True   42 ms  Kelly
True  121 ms  Yevhen
True  132 ms  Ch3ster

True   97 ms  original
True   42 ms  Kelly
True  119 ms  Yevhen
True  129 ms  Ch3ster

Benchmark with 500 numbers from -500 to 500, since you just commented your lists are "few 100 elements long" (Try it online!):

True  233 us  original
True   85 us  Kelly
True  192 us  Yevhen
True  198 us  Ch3ster

True  231 us  original
True   83 us  Kelly
True  192 us  Yevhen
True  195 us  Ch3ster

True  229 us  original
True   87 us  Kelly
True  194 us  Yevhen
True  196 us  Ch3ster
  • Related