# Order a list but respect integer ordering (natural sort order) [closed]

Given a list of n strings, return a list of that strings in ascending order. However, be aware, that in this case we want integer comparison for all numbers appearing in the strings, meaning that "12" > "3".

Example cases:

{"abc123", "abc6", "abc47", "abd49"} -> {"abc6", "abc47", "abc123", "abd49"}
{"foo0", "bar12", "foobar12", "foo"} -> { "bar12", "foo", "foo0", "foobar12"}
{"Bond007", "Bond07", "Bond7", "Bond12"} -> {"Bond007", "Bond07", "Bond7", "Bond12"}
{"one1", "one11two23", "one1two2", "one1two3", "1"} -> {"1", "one1", "one1two2", "one1two3", "one11two23"}


You can expect to only find [a-zA-Z0-9]+ in each string. This is so shortest code in bytes wins. Standard Loopholes are forbidden.

Update:
- Sorting is case insensitive
- The ascending order is integers < "abcdefghijklmnopqrstuvwxyz"
- Every sequence of integers as in the aforementioned order should be interpreted as one integer, meaning "421" represents 421, not 4, 2 and 1 and thus is smaller than "1341", as 421 < 1341

-Treat numbers with leadings zeroes as though they were decimals meaning "001" -> "0.01" so "001" < "01" < "1"

Thanks for Adám for pointing out, that this is called natural sort order.

• Unfortunately, there are a lot specifications missing here. – Adám Feb 22 '18 at 1:53
• Also, it's still unclear what to do about 01 vs. 010. – Ørjan Johansen Feb 22 '18 at 3:38
• The decimals' rule doesn't make any sense. I think what you want is that otherwise identical numbers, but where some have leading zeros, should sort by length, longest first, right? – Adám Feb 22 '18 at 7:49
• Since the case insensitivity leads to ties you have to specify if the sort has to be stable or not. I suggest not since otherwise you force people whose language sort is unstable to implement their own sort – Ton Hospel Feb 22 '18 at 8:42
• This is a nice challenge I'd like to do but the spec is still incomplete. So could you please update your question ? The only things you still need to do is to specify how ties in the sorting are to be handled and fix the rule for leading zeros (presumably saying that more leading zeros sort before less leading zeros instead of trying to get to this using fractions). – Ton Hospel Feb 27 '18 at 8:53

# 05AB1E, 7 bytes

ΣDþïs)}


Try it online!

# Explanation

ΣDþïs)}  Full Program
Σ     }  Sort by result of key: a
D       a, a
þ      digits_only(a), a
ï     int(digits_only(a)), a
s    a, int(digits_only(a))
)   [a, int(digits_only(a))]


# Python 2, 68 bytes

lambda l:sorted(l,key=lambda x:int(re.sub("\D","",x)or 0))
import re


Try it online!

I used something like this to sort PDF files recently!

my entry originally didn't work but Neil fixed it (thanks!)

# Perl 6,  32 31  30 bytes

*.sort(*.comb(/\d+|\D+/)».&val)


Test it

*.sort(*.comb(/\d+|\D/)».&val)


Test it

*.sort(*.comb(/\d+|./)».&val)


Test it

## Expanded:

*\                         # WhateverCode lambda (this is the parameter)

.sort(                     # sort by doing the following to each string

*.comb( / \d+ | . / )\ # split the string into consecutive digits or a character

».&val                   # convert each to a Numeric if possible

)


Note:

"Bond007".comb(/\d+|\D+/)».&val
# results in
("Bond", IntStr.new(7, "007"))

# and

"Bond007".comb(/\d+|./)».&val
# results in
("B", "o", "n", "d", IntStr.new(7, "007"))


# APL (Dyalog Unicode) 17.0 (currently in alpha), 31 bytesSBCS

Anonymous tacit prefix function taking a list of strings as argument.

⊂⊃¨⍨∘⍋({0::⍵⋄⍎⍵}¨⊢⊂⍨1,2≠/∊∘⎕D)¨


As version 17.0 isn't on TIO yet, here is a test session transcript:

      f←⊂⊃¨⍨∘⍋({0::⍵⋄⍎⍵}¨⊢⊂⍨1,2≠/∊∘⎕D)¨
⎕JSON f ⎕JSON '["abc123", "abc6", "abc47", "abd49"]'
["abc6","abc47","abc123","abd49"]
⎕JSON f ⎕JSON '["foo0", "bar12", "foobar12", "foo"]'
["bar12","foo","foo0","foobar12"]
⎕JSON f ⎕JSON '["Bond007", "Bond07", "Bond7", "Bond12"]'
["Bond007","Bond07","Bond7","Bond12"]
⎕JSON f ⎕JSON '["one1", "one11two23", "one1two2", "one1two3", "1"]'
["1","one1","one1two2","one1two3","one11two23"]


⊂ from the entire argument…

⊃¨⍨ pick each of the indices…

∘ that are…

⍋ the ascending grade (indices which would place in ascending order) of…

()¨ the following tacit function applied to each of the strings:

∊∘⎕D Boolean mask for the characters which are members of the set of Digits

2≠/ pairwise inequality of that (i.e. indicate beginnings of letter runs and digit runs)

1, prepend 1 to mark the first character as beginning a run

⊢⊂⍨ use that to partition (beginning partitions at 1s) the string

{}¨ apply the following anonymous lambda to each partition:

0:: if any error happens, then:
⍵ return the argument as-is

⋄ try to:
⍎⍵ evaluate the argument

# Python 3, 107 106 bytes

import re
lambda a:sorted(a,key=lambda x:[n.isdigit()and n.zfill(9)or n for n in re.findall('\d+|\D+',x)])


Try it online!

Abused the fact that Python compares two lists lexicographically. Unfortunately re.split(r'\b',x) does not work.

• r'... -> '.... – Jonathan Frech Feb 22 '18 at 1:48
• Thanks, I didn't know that works. – Bubbler Feb 22 '18 at 1:50

# Python 2, 92 bytes

lambda q:map(lambda a:a[1],sorted(map(lambda a:[int(re.sub("\D","",a)or 0),a],q)))
import re


Try it online!

# Python 3, 125 bytes

lambda a:[y for _,y in sorted([([i%2and int(e)or e for i,e in enumerate(re.findall("(\D+|\d+)",s))],s)for s in a])]
import re


Try it online!

# PHP 7, 17 bytes

<?php natsort()?>


natsort"Sort an array using a 'natural order' algorithm"