-3

I want to sort a list in Python3, first odd numbers, then even numbers.
Let the list is li = [4, 1, 5, 8, 2, 9, 3, 10, 7, 6]
Output should be: 1 3 5 7 9 2 4 6 8 10
How to solve this using function or lambda or any other way?

#Edited
using lambda only.

Bishwanath
  • 19
  • 6

5 Answers5

3

You're effectively sorting on two keys: the primary key is whether the int is even or odd, and you want odd to compare "smaller". The secondary key is then the integer itself. That can all be expressed by sorting on tuples of (primary key, secondary key), which can be expressed by building those tuples straightforwardly via a function passed to sorting's optional key= argument:

>>> li = [4, 1, 5, 8, 2, 9, 3, 10, 7, 6]
>>> sorted(li, key=lambda i: (1 - (i & 1), i))
[1, 3, 5, 7, 9, 2, 4, 6, 8, 10]

Alternative: in any case where you're sorting on N keys, instead of doing a single sort with N-tuple keys, you can instead do N sorts on the individual keys, least-significant key first. This may well not be obvious, and relies on that Python's sorting algorithm is "stable" (preserves the input order of items that compare equal). Concretely, for the case at hand, here's one way to do that:

>>> sorted(sorted(li), key=lambda i: i % 2, reverse=True)
[1, 3, 5, 7, 9, 2, 4, 6, 8, 10]

For reasons that are uncomfortably involved, it can be faster to do it this way. Despite that you're doing more sorts, it's possible that cheaper comparisons can more than make up for that.

Tim Peters
  • 67,464
  • 13
  • 126
  • 132
  • 1
    I'm glad *someone* posted the elegant way before I got to the question. Nice to see it's the person responsible for the implementation of `sorted`. Good to see you again, BTW. I think last time was [eight years ago, to the day in fact.](https://stackoverflow.com/questions/21297887/performance-issues-in-burrows-wheeler-in-python/) – Karl Knechtel Jan 23 '22 at 18:23
  • 1
    Although I think I would have written it as (edited on slight reconsideration) `(-(i % 2), i)` :) – Karl Knechtel Jan 23 '22 at 18:26
  • Neat solution using bitwise operator – Mario Saraiva Jan 23 '22 at 18:27
  • Alternatively, this will do it - ```L.sort(key=lambda x: ((x%2 == 0), x))``` – Daniel Hao Oct 08 '22 at 19:08
1

We take the list, filter only the odd values, sort, and splat the values and do the exact same but for evens.

li = [4, 1, 5, 8, 2, 9, 3, 10, 7, 6]
final_li = [*sorted(filter(lambda x: x % 2, li)), *sorted(filter(lambda x: x % 2 == 0, li))]
Mario Saraiva
  • 421
  • 3
  • 4
0

here is one way (if there is no duplicate number in the list):

li = [4, 1, 5, 8, 2, 9, 3, 10, 7, 6]
sorted_li = sorted(li)
print([*sorted_li[::2] , *sorted_li[1::2]])

output:

[1, 3, 5, 7, 9, 2, 4, 6, 8, 10]

I'm sorting the whole list once , then make a new list by slicing that sorted list , which first I pick odd numbers , which since they are sorted , are every other number from index 0 , and then even numbers , the same concept , this time even numbers start from index 1 , then I unpack them into one list in that order

eshirvana
  • 23,227
  • 3
  • 22
  • 38
  • I would greatly appreciate it if you could explain the list comprehension part. I can solve this, but not with list comprehension. – PSR Jan 23 '22 at 18:03
  • it's called `slicing` , – eshirvana Jan 23 '22 at 18:09
  • Oh, I was unaware, my bad. – PSR Jan 23 '22 at 18:09
  • So what exactly is happening in the slicing part ? – PSR Jan 23 '22 at 18:10
  • @PSR I'm sorting the whole list once , then make a new list by slicing that sorted list , which first I pick odd numbers , which since they are sorted , are every other number from index 0 , and then even numbers , the same concept , this time even numbers start from index 1 , then I unpack them into one list in that order – eshirvana Jan 23 '22 at 18:13
  • This solution only works if after sorting the list we have interchanging odd and even numbers. If after sorting we have two consecutive odd or even numbers, this fails. – Mario Saraiva Jan 23 '22 at 18:14
  • @MarioSaraiva good point – eshirvana Jan 23 '22 at 18:17
0

This should work:

array = [4, 1, 5, 8, 2, 9, 3, 10, 7, 6]

even = []
odd = []

for value in sorted(array):
    if value % 2 == 0:
        even.append(value)
    else:
        odd.append(value)
        
combined = even + odd

print(*combined)
0

Using a tuple as the sort key is the usual way to approach this:

li = sorted(li,key=lambda n: (1-n%2,n))

Alternatively you can separate the odds and evens before sorting and concatenate the results. If the spread between odds and evens is roughly equal, this will run two smaller sorts instead of a big one.

odds  = (n for n in li if n%2)      # generators, avoid using extra memory
evens = (n for n in li if n%2==0)   # you could also use filter()
li    = sorted(odds)+sorted(evens)
print(li)
[1, 3, 5, 7, 9, 2, 4, 6, 8, 10]
Alain T.
  • 40,517
  • 4
  • 31
  • 51