0

I can't seem to find any information on how to correctly sort a list like this. My list looks something like this

["1. Banana", "2. Pear", "11. Apple", "5. Grapes", "4. Orange"]

Using sorted() leaves me with the following

['1. Banana', '11. Apple', '2. Pear', '3. Orange', '4. Grapes']

and I would like it to come out like this

['1. Banana', '2. Pear', '3. Orange', '4. Grapes', '11. Apple']


If it adds any complications I need to use this to sort a list of dictionaries using a specific key's value, so my current code is
list.sort(key=lambda k: k["key"])
jpp
  • 159,742
  • 34
  • 281
  • 339
  • Wait, why are you using `list.sort(key=lambda k: k["key"])`? I see no dictionaries in your example. Anyway, what you'll have to do is sort by the *int value of the number* since that is what you seem to want. You can parse out that int. Indeed, if that is something you want, you should have used a different data-structure in the first place, i.e. `(1, 'Banana')` and only construct the final string when you need it. – juanpa.arrivillaga Feb 17 '18 at 20:22
  • 2
    I think your question's answer is there : https://stackoverflow.com/questions/5967500/how-to-correctly-sort-a-string-with-a-number-inside – syny Feb 17 '18 at 20:24
  • 1
    @syny that's exactly what I was looking for, thank you . I neglected to mention in the question that some items of the list may not have a leading number but your suggestion is perfect and now I know what it's called! –  Feb 17 '18 at 21:27

3 Answers3

5

Sort by . separated first int value as sorting key:

sorted(lst, key=lambda x: int(x.split('.')[0]))

Example:

In [20]: lst = ["1. Banana", "2. Pear", "11. Apple", "5. Grapes", "4. Orange"]

In [21]: sorted(lst, key=lambda x: int(x.split('.')[0]))
Out[21]: ['1. Banana', '2. Pear', '4. Orange', '5. Grapes', '11. Apple']
heemayl
  • 39,294
  • 7
  • 70
  • 76
  • sorry, didn't see your solution, until i submit my answer, which was identical to yours. – marmeladze Feb 17 '18 at 20:26
  • 2
    @marmeladze No problem. We were probably writing at the same time; mine came just a bit earlier i guess. It happens :) – heemayl Feb 17 '18 at 20:27
  • 1
    Yeah @marmeladze, it's no big deal. I happens to the best of us - even to me ;-) I was just trying to give you heads up. – Christian Dean Feb 17 '18 at 20:31
  • @heemayl hey thank you for the quick answer! I didn't think ahead when posting my question and over-simplified the example list, not all of the strings I need to sort have a leading number. How would you go about sorting that? –  Feb 17 '18 at 20:49
  • @Flameout Hard to say without seeing a concrete example. Also, i think it would be better if you ask it as a new question with all the details. – heemayl Feb 17 '18 at 20:51
4

For a bit more robust solution, grab the digit from the string items using regex, and use that to sort your list:

>>> from re import compile
>>> 
>>> regex = compile('\d+')
>>> lst = ["1. Banana", "2. Pear", "11. Apple", "5. Grapes", "4. Orange"]
>>> sorted(lst, key= lambda el: int(regex.search(el).group()))
['1. Banana', '2. Pear', '4. Orange', '5. Grapes', '11. Apple']
>>> 

That way, you code won't fail even if the digit isn't the first part of your strings:

>>> lst = ["Banana 1.", "2. Pear", "11. Apple", "5. Grapes", "4. Orange"]
>>> sorted(lst, key= lambda el: int(regex.search(el).group()))
['Banana 1.', '2. Pear', '4. Orange', '5. Grapes', '11. Apple']
>>> 
Christian Dean
  • 22,138
  • 7
  • 54
  • 87
3

In my opinion, you should be storing this data as a dictionary:

lst = ["1. Banana", "2. Pear", "11. Apple", "5. Grapes", "4. Orange"]

d = dict((int(j[0]), j[1]) for j in [i.split('. ') for i in lst])

# {1: 'Banana', 2: 'Pear', 4: 'Orange', 5: 'Grapes', 11: 'Apple'}

Then sorting is trivial:

sorted(d.items())

# [(1, 'Banana'), (2, 'Pear'), (4, 'Orange'), (5, 'Grapes'), (11, 'Apple')]

And so is formatting:

['. '.join((str(a), b)) for a, b in sorted(d.items())]

# ['1. Banana', '2. Pear', '4. Orange', '5. Grapes', '11. Apple']
jpp
  • 159,742
  • 34
  • 281
  • 339
  • 2
    It's not that big of an improvement, but it seems using `str.format` over `str.join` is a _tiny bit faster_: https://ideone.com/6iXDXs. Like I said though, in practice the difference probably wouldn't matter. – Christian Dean Feb 17 '18 at 20:36