0

I am beginner in python lists. I have a list of feature classes named by type and year of occurrence: feature class "a_05" occurred in 2005, feature class "b_03" occurred in 2003.

I would like to sort the items in a list increasingly by time they occurred (2003, 2005...), and if two types occurred in the same year, than they should be ordered alphabetically.

Let's say, list

fcs = [u'b_02', u'a_05', u'a_03', u'b_03']

should results in [ u'b_02', u'a_03', u'b_03', u'a_05'],

i.e. first years (_02,_03,_03,_05) and then alphabetically u'a_03', u'b_03'.

Using simply fcs.sort() my items are instead first sorted alphabetically, than by numbers: [u'a_03', u'a_05', u'b_02', u'b_03']

How can I alter my item names to be able to sort them first by numbers, not by the letters?

maycca
  • 3,848
  • 5
  • 36
  • 67
  • `print(sorted(fcs, key=lambda x: int(x.split("_")[1])))` – Rakesh May 08 '19 at 14:14
  • 1
    Just to help out, there are some great examples [here](https://stackoverflow.com/questions/4836710/does-python-have-a-built-in-function-for-string-natural-sort) that describe all _sorts_ of different ways to `sort` – MyNameIsCaleb May 08 '19 at 14:18

3 Answers3

3

Using sorted with a custom key.

Ex:

fcs = [u'b_02', u'a_05', u'a_03', u'b_03']
print(sorted(fcs, key=lambda x: int(x.split("_")[1])))

or sort

Ex:

fcs = [u'b_02', u'a_05', u'a_03', u'b_03']
fcs.sort(key=lambda x: int(x.split("_")[1]))
print(fcs)

Output:

['b_02', 'a_03', 'b_03', 'a_05']

Using the lambda function to split the element by _ and then converting it to int

Rakesh
  • 81,458
  • 17
  • 76
  • 113
1
fcs = [u'b_02', u'a_05', u'a_03', u'b_03']
fcs.sort(key=lambda x:[int(x.split('_')[1]),x.split('_')[0]])

output

['b_02', 'a_03', 'b_03', 'a_05']

full documentation for using lambda here

here i am making an order to sort, sort list with method 1 and if in method 1 got few value which are same then sort those same values with the method 2 (it's like nested sorting). order to sort is defined in a list.

method 1 : x.split('_')[1]] # on bases of integer

method 2 : x.split('_')[0]] # on bases of alphabets

PS. sorry i am bad at explaining stuff.

sahasrara62
  • 10,069
  • 3
  • 29
  • 44
0

In the case of simple comparisons you can use key argument with lambda function that defines what exactly you want to compare (you can see it in the another answer). But sometimes you will lack the key argument. In this case you can use cmp_to_key function from the functools module. It allows you to do complicated comparisons inside the function, wrap it with this function and send to sorted() function as key argument. Here is the example:

from functools import cmp_to_key

fcs = [u'b_02', u'a_05', u'a_03', u'b_03']

def waka(s1, s2):
    name1, year1 = s1.rsplit('_', 1)
    name2, year2 = s2.rsplit('_', 1)
    if year1 > year2:
        return 1
    elif year1 < year2:
        return -1
    elif name1 > name2:
        return 1
    elif name1 < name2:
        return -1
    else:
        return 0

sorted(fcs, key=cmp_to_key(waka))


['b_02', 'a_03', 'b_03', 'a_05']
vurmux
  • 9,420
  • 3
  • 25
  • 45