2

I want to sort a list based on how close a number in the list is to a given number. So for example:

target_list = [1,2,8,20]
number = 4

then probably sorted list is [2,1,8,20] since:

   4-2 = 2
   4-1 = 3
 |4-8| = 4
|4-20| = 16

In case of collision, I don't really care which one comes first but then I am trying to sort the list on the basis of this distance metric. What is the best (and pythonic) way to do this?

martineau
  • 119,623
  • 25
  • 170
  • 301
frazman
  • 32,081
  • 75
  • 184
  • 269

3 Answers3

13

You can use the key parameter of the sorted function

>>> target_list = [1,2,8,20]
>>> sorted(target_list, key=lambda x: abs(4-x))
[2, 1, 8, 20]

Or if you want to sort it in place, even the list sort method accepts a key.

>>> target_list.sort(key=lambda x: abs(4-x))
>>> target_list
[2, 1, 8, 20]
Praveen Gollakota
  • 37,112
  • 11
  • 62
  • 61
  • the lambda bugs me. anyone got a nice oneline solution without? `sorted(target_list, key=partial(operator.add, -number))` obviously misses the `abs()` :( – ch3ka Apr 23 '12 at 19:54
  • @ch3ka It may be achieve with using [`functional` module](http://docs.python.org/release/3.1.5/howto/functional.html#the-functional-module) by composing `operator.add` and `abs`. – ovgolovin Apr 23 '12 at 22:22
  • @ch3ka But I think `lambda` would look better! Raymond Hettinger recently wrote about all those `partial`s: https://twitter.com/#!/raymondh/status/183686911112646657 – ovgolovin Apr 23 '12 at 22:26
  • don't get me wrong, ovgolovin. I *love* lambda. But it kinda bugs me, that this simple statement cannot be done simply without. – ch3ka Apr 23 '12 at 22:28
4
sorted(target_list, key=lambda k: abs(k - 4))

Or to sort the list in place:

target_list.sort(key=lambda k: abs(k - 4))
Andrew Clark
  • 202,379
  • 35
  • 273
  • 306
1
>>> target_list.sort(key=lambda x: abs(number-x))
>>> target_list
[2, 1, 8, 20]
ovgolovin
  • 13,063
  • 6
  • 47
  • 78