0

I want to sort a list of numeric strings (w/ trailing zeroes) like how you normally sort number. I'd also like to return a True bool if a provided numeric string is in that list.

Example:

old_list = [1.1, 1.8, 1.50, 1.5, 1.9, 2.1]

to

sorted = [1.1, 1.5, 1.8, 1.9, 1.50, 2.1]

So, obviously the decimals are treated like numbers and sorted like numbers. 1.50 should not be simplified as 1.5, etc. It is used for product id for my company and has been bothering me for a year already.

I have tried converting the numeric strings into str then sort. I also tried using the Decimal module but it turns 1.1 into sth like 1.10000000000000008881...

Here is the code I used:

object_num = list(map(str, ['1.1', '1.8', '1.50', '1.5', '1.9', '2.1']))
object_num.sort()
print(object_num)

Result:

['1.1', '1.5', '1.50', '1.8', '1.9', '2.1']

I appreciate that Python is smart enough to sort the list numerically, but I hope it could also get me this result:

sorted = [1.1, 1.5, 1.8, 1.9, 1.50, 2.1]

And when I typed

print(1.50 in sorted)

It could return True.

Edit1: sorry for not making myself clear. Let me explain the numbering system my company is using:

ID for first product from series A: 1.1

ID for second product from series A: 1.2

...

ID for fiftieth product from series A: 1.50

ID for first product from series B: 2.1

All I want is to sort products from series A first, then series B

Thus, 1.5 is indeed different from 1.50 in my case

september 21st
  • 187
  • 1
  • 7
  • Why would ``1.50`` be larger than ``1.9``? It seems you do *not* want them treated as decimals, but as tuples - ``1, 50`` and ``1, 9``. – MisterMiyagi Aug 09 '19 at 16:01
  • If there are a lot of products, there may be a use for set. It has much faster existence checks, but it doesn't go as well with sorting. – Kenny Ostrom Aug 09 '19 at 16:11
  • Oh, 1.50 is (one, fifty) sorry misunderstood that completely. – Kenny Ostrom Aug 09 '19 at 16:14
  • I would also like to find out who invented this numbering system – september 21st Aug 09 '19 at 16:18
  • 1
    "like how you normally sort number" is not a very clear description of what you're trying to achieve here. Normally, I would think 5 is less than 50 (and 1.5 is the same as 1.50). Do you mean "how you would normally sort *version numbers*"? – wovano Aug 10 '19 at 10:19
  • sorry for not making myself clear. Let me explain the numbering system my company is using: ID for first product from series A: 1.1 ID for second product from series A: 1.2 ... ID for fiftieth product from series A: 1.50 ID for first product from series B: 2.1 All I want is to sort products from series A first, then series B Thus, 1.5 is indeed different from 1.50 in my case – september 21st Aug 10 '19 at 14:54
  • So it's not really a "numeric string" then, but a version number. (That's why I added an answer using `distutils.version`) Sorting numeric strings is something different. – wovano Aug 13 '19 at 16:22

2 Answers2

2

One solution using re module:

import re

lst = ['1.1', '1.8', '1.50', '1.5', '1.9', '2.1']

l = sorted(lst, key=lambda k: [*map(int, re.findall(r'\d+', k))])
print(l)

Prints:

['1.1', '1.5', '1.8', '1.9', '1.50', '2.1']

Or without re:

l = sorted(lst, key=lambda k: [*map(int, k.split('.'))])
print(l)
Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
  • 1
    This looks to be the answer OP wanted, I was going to suggest the no `re` solution. – Mason Caiby Aug 09 '19 at 16:01
  • 1
    It works! thank you very much... After a while of googling, I found an alternative, using the natsort module: ```print(natsort.natsorted(object_num))``` This achieves the same result. It turns out natural sort is what I was looking for! – september 21st Aug 09 '19 at 16:14
  • 1
    thank you soo much @andrej-kesely! You saved my day! I spent hours doing this – Ankit Brijwasi Jan 14 '22 at 05:34
0

For version numbers you could use the (unfortunately not so well documented) distutils.version module:

from distutils.version import LooseVersion  # or StrictVersion

object_num = ['1.1', '1.8', '1.50', '1.5', '1.9', '2.1']
object_num.sort(key=LooseVersion)
print(object_num)

Result:

['1.1', '1.5', '1.8', '1.9', '1.50', '2.1']

It will also handle version numbers like "1.5.2b2" (e.g. for beta versions or release candidates). Depending on your needs you can choose between LooseVersion or StrictVersion (see the docstrings for the differences between them).

wovano
  • 4,543
  • 5
  • 22
  • 49