0

I have an array with these datas:

[['1', '7', '14'], ['1', '1', '3'], ['1', '12', '3'], ['2', '3', '1'], ['1', '4', '9']]

I like to sort it (multiple):

>>> sorted(datas,key=lambda x:(x[0], x[1]))
[['1', '1', '3'], ['1', '12', '3'], ['1', '4', '9'], ['1', '7', '14'], ['2', '3', '1']]    

but after sorted as it seems the 12 < 4. It should be:

[['1', '1', '3'], ['1', '4', '9'], ['1', '7', '14'], ['1', '12', '3'], ['2', '3', '1']]

Any idea? I need not natural sorting.

Sotech
  • 109
  • 1
  • 7
  • 1
    possible duplicate of [Does Python have a built in function for string natural sort?](http://stackoverflow.com/questions/4836710/does-python-have-a-built-in-function-for-string-natural-sort) – MJeffryes Mar 27 '15 at 17:02
  • 1
    The issue is nothing to do with the fact you are sorting by multiple keys, it is simply that the string '12' *is* less than '4'. You want to use a natural sort, or alternatively you can cast the strings to `int` – MJeffryes Mar 27 '15 at 17:03
  • vaultah wrote the good solution yet, but deleted it. – Sotech Mar 27 '15 at 17:07
  • Thanks MJeffryes the cast the string to int is a right solution. – Sotech Mar 27 '15 at 17:10

4 Answers4

2

There is not wrong with sorted behaviour. Your data are lists of string, so it's doable.

>>> data = ['1', '12', '3', '2']
>>> sorted(data)
['1', '12', '2', '3']

If you want to sort as integer, it must be converted.

>>> sorted(data)
['1', '12', '2', '3']
>>> data = [['1', '7', '14'], ['1', '1', '3'], ['1', '12', '3'], ['2', '3', '1'], ['1', '4', '9']]
>>> sorted(data, key=lambda x: map(int, x))
[['1', '1', '3'], ['1', '4', '9'], ['1', '7', '14'], ['1', '12', '3'], ['2', '3', '1']]
Mauro Baraldi
  • 6,346
  • 2
  • 32
  • 43
1

Convert x[1] to int(x[1]):

sorted(d,key=lambda x:(int(x[0]), int(x[1])))

Output:

[['1', '1', '3'], ['1', '4', '9'], ['1', '7', '14'], ['1', '12', '3'], ['2', '3', '1']]
Uyghur Lives Matter
  • 18,820
  • 42
  • 108
  • 144
Sakib Ahammed
  • 2,452
  • 2
  • 25
  • 29
1

You are comparing strings, not ints. Therefor the order you get is the lexicographical order. If you convert to int first

sorted(data, key=lambda x:(int(x[0]), int(x[1])))

you will get the desired result

[['1', '1', '3'], ['1', '4', '9'], ['1', '7', '14'], ['1', '12', '3'], ['2', '3', '1']]
chokola
  • 13
  • 1
  • 3
  • It's answer looks like my answer. but I answer this first, may be 3 mins before @Sotech & chokola – Sakib Ahammed Mar 27 '15 at 17:23
  • 1
    @SakibAhammed Sometimes when an answer is simple enough, multiple people do legitimately post nearly the same answer within the first few minutes. – Uyghur Lives Matter Mar 27 '15 at 17:29
  • @cpburnz...Hmm i know that. but he was posted after 3 mins from me, this is a so much time for that answer – Sakib Ahammed Mar 27 '15 at 17:36
  • @SakibAhammed It's not really that long. If someone came to this page before anyone answered, and then went to write an answer, they would not know an answer was posted a couple minutes earlier until they post it and reload the page. The new answer notifications are not perfect or instant (and can be missed). – Uyghur Lives Matter Mar 27 '15 at 17:38
  • 1
    You're right Sakib. Sorry I didn't look through the answers thoroughly. The points are yours. – Sotech Mar 27 '15 at 19:49
0

Currently your sort is working on tuples string values. String values are determined similarly to any other iterable. When it compares two strings, it goes character by character from left-to-right or index 0 to index n-1 where n is the length of the iterable, until it finds one character that is larger than another. so when comparing '12' and '4', it notices that '4' is greater than '1' so it finishes right there. This system of ordering is known as lexicographical order.

To see the "value" of a character (In Python, a character is just a string of length 1), just use the ord function:

>>> ord('1')
49
>>> ord('4')
52

And to validate that the string '12' is indeed less than '4' because ord('1') < ord('4'):

>>> '12' < '4'
True

If you want to sort by the integer values of the strings, you have to convert the strings to ints by using the built-in int constructor.

sorted(datas,key=lambda x: (int(x[0]), int(x[1]))

Or if you want to cleanly handle iterables of all sizes, simply use a tuple-generator for the key:

sorted(datas,key=lambda x: tuple(int(e) for e in x))
Shashank
  • 13,713
  • 5
  • 37
  • 63