Sort in list comprehension

Question:

I have some data that looks like this

my_list = ['10 apples', '4 dogs', '9 cats']

I need to do some string modification to the the items in the list and then create two new lists.

headers = [words.replace(' ', '_') for words in my_list]
numbers= [nums.split()[0] for nums in my_list]

Is there a way to sort these inside of the list comprehension? Right now i’m doing this, which isn’t a big deal, but I thought I’d take this opportunity to learn if possible.

# Create lists
headers = [my_list.replace(' ', '_') for words in my_list]
numbers= [my_list.split()[0] for nums in my_list]

# Sort Lists
headers.sort(reverse = True)
numbers.sort(reverse = True)

I’m doing this in a pyspark environment, if that makes a difference.

Asked By: pkpto39

||

Answers:

There is no method to sort inside a list comprehension (There actually kind of is one. See Edit at the bottom). But using sorted() you can still do it in one line each.

headers = sorted([words.replace(' ', '_') for words in my_list], reverse=True)
numbers = sorted([nums.split()[0] for nums in my_list], reverse=True)

Output:

['9_cats', '4_dogs', '10_apples']
['9', '4', '10']

With this code numbers will be a list of strings so they will be sorted lexicographically, not as numbers.
To fix this just use int() in the comprehension and convert from string to integer. Or convert it while sorting so you will keep a list of strings.

# option 1
numbers = sorted([int(nums.split()[0]) for nums in my_list], reverse=True)
# option 2
numbers = sorted([nums.split()[0] for nums in my_list], reverse=True, key=lambda x: int(x))

Output:

Option 1
[10, 9, 4]
Option 2
['10', '9', '4']

I don’t know how you want the headers list to be sorted. But if you want it be sorted by the words after _ (‘apples’, ‘dogs’, ‘cats’)
you can do the following

headers = sorted([words.replace(' ', '_') for words in my_list], reverse=True, key=lambda x: x.split('_')[1])

Output:

['4_dogs', '9_cats', '10_apples']

Edit


Quoting User xavi

Adding to the last solution: If using sorted with that lambda, there isn’t really any reason to keep it outside the list comprehension, which accomplishes the stated goal of sorting "inside the comprehension"

headers = [words.replace(' ', '_') for words in sorted(my_list, reverse=True, key=lambda x:x.split()[1])]

The same applies to numbers

numbers = [nums.split()[0] for nums in sorted(my_list, reverse=True, key=lambda x:int(x.split()[0]))]
Answered By: noah1400

Is there a way to sort these inside of the list comprehension?

A list comprehension is just a linear scan over list elements. Since it’s impossible to do a comparison sort in linear time, a list comprehension cannot be used for sorting inputs.

If your question is about writing more compact code though you could call sorted() on the result of a list comprehension expression.

my_list = ['10 apples', '4 dogs', '9 cats']

headers = sorted(
  [word.replace(' ', '_') for word in my_list], 
  key = lambda word: int(word.split('_')[0]), 
  reverse = True)
numbers = sorted([int(word.split()[0]) for word in my_list], reverse = True)

print(headers)
print(numbers)

Output:

['10_apples', '9_cats', '4_dogs']
[10, 9, 4]
Answered By: Alex Yursha