# Sorting strings containing numbers, so that "A2" \< "A10"?

**URL:** <https://discourse.julialang.org/t/sorting-strings-containing-numbers-so-that-a2-a10/5372>\
**Category:** General Usage\
**Tags:** strings, sort\
**Created:** [August 14, 2017, 9:37am UTC](https://discourse.julialang.org/t/sorting-strings-containing-numbers-so-that-a2-a10/5372 "2017-08-14T09:37:27Z")\
**Posts on this page:** 9\
**Page:** 2

<div class="post-metadata">

**Author:** ![jandehaan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jandehaan/32/6805_2.png) [@jandehaan](https://discourse.julialang.org/u/jandehaan)\
**Post date:** [July 13, 2020, 12:10am UTC](https://discourse.julialang.org/t/sorting-strings-containing-numbers-so-that-a2-a10/5372/21 "2020-07-13T00:10:13Z")

</div>

“k(x)” in the statement “A = k(x)” means apply function k to the value of parameter x. You supply this value when you call the function natural(x,y).

“k(x)” in “k(x) = [occursin …” means “define the function k as k(x)=[occursin …”

When you call "natural(“A2”, “A10”), the call A=k(x) results in A=[“A”, 2] and the call B=“A10” results in B=[“A”, 10]. Subsequently the string “A” is compared to the string “A” and the integer 2 is compared to the integer 10.

---

<div class="post-metadata">

**Author:** ![evad](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evad/32/15756_2.png) [@evad](https://discourse.julialang.org/u/evad)\
**Post date:** [July 13, 2020, 12:22pm UTC](https://discourse.julialang.org/t/sorting-strings-containing-numbers-so-that-a2-a10/5372/22 "2020-07-13T12:22:37Z")

</div>

Thanks…And the return within for loop and last line `return length(A) < length(B)`. What would these be generating?

---

<div class="post-metadata">

**Author:** ![jandehaan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jandehaan/32/6805_2.png) [@jandehaan](https://discourse.julialang.org/u/jandehaan)\
**Post date:** [July 14, 2020, 8:44pm UTC](https://discourse.julialang.org/t/sorting-strings-containing-numbers-so-that-a2-a10/5372/23 "2020-07-14T20:44:13Z")

</div>

The length of zip(A, B) is the shorter of the lengths of A and B. If all the elements in the shorter array match the corresponding elements in the longer array, the for loop ends without returning anything. At that point the statement “return length(A) \< length(B)” is executed. It returns true (that is x is less than y) if A has fewer elements than B.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [July 14, 2020, 9:11pm UTC](https://discourse.julialang.org/t/sorting-strings-containing-numbers-so-that-a2-a10/5372/24 "2020-07-14T21:11:02Z")

</div>

Note that `natural` will ignore spaces. I suppose that may be a feature, though.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [July 14, 2020, 9:13pm UTC](https://discourse.julialang.org/t/sorting-strings-containing-numbers-so-that-a2-a10/5372/25 "2020-07-14T21:13:11Z")

</div>

Note that [NaturalSort.jl](https://github.com/JuliaStrings/NaturalSort.jl) was moved to [JuliaStrings](https://github.com/JuliaStrings) and was updated to work with Julia 1.x.

So, I would tend to recommend the NaturalSort package for people who want this kind of ordering.

---

<div class="post-metadata">

**Author:** ![Znerual](https://avatars.discourse-cdn.com/v4/letter/z/6de8d8/32.png) [@Znerual](https://discourse.julialang.org/u/Znerual)\
**Post date:** [November 12, 2020, 4:25pm UTC](https://discourse.julialang.org/t/sorting-strings-containing-numbers-so-that-a2-a10/5372/26 "2020-11-12T16:25:17Z")

</div>

The code is great, but you might want to change sort to sort!, in order to get l sorted.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [November 12, 2020, 9:08pm UTC](https://discourse.julialang.org/t/sorting-strings-containing-numbers-so-that-a2-a10/5372/27 "2020-11-12T21:08:59Z")

</div>

@pfitzeb, both `matchall` and `isnumber` seem to have been deprecated. Would the following update be correct for Julia 1.5.2?

```julia
function sort_pfi(x::Vector{String})
    f = text -> all(isnumeric, text) ? Char(parse(Int, text)) : text
    sorter = key -> join(f(c) for c in collect(m.match for m in eachmatch(r"[0-9]+|[^0-9]+", key)))
    sort(x, by=sorter)
end

```

Thank you.

---

<div class="post-metadata">

**Author:** ![pfitzseb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pfitzseb/32/45566_2.png) [@pfitzseb](https://discourse.julialang.org/u/pfitzseb)\
**Post date:** [November 12, 2020, 9:13pm UTC](https://discourse.julialang.org/t/sorting-strings-containing-numbers-so-that-a2-a10/5372/28 "2020-11-12T21:13:35Z")

</div>

That works, although I’d get rid of the `collect`:

```julia
function sort_pfi(x::Vector{String})
    f = text -> all(isnumeric, text) ? Char(parse(Int, text)) : text
    sorter = key -> join(f(m.match) for m in eachmatch(r"[0-9]+|[^0-9]+", key))
    sort(x, by=sorter)
end

```

---

<div class="post-metadata">

**Author:** ![pfitzseb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pfitzseb/32/45566_2.png) [@pfitzseb](https://discourse.julialang.org/u/pfitzseb)\
**Post date:** [August 16, 2021, 7:50pm UTC](https://discourse.julialang.org/t/sorting-strings-containing-numbers-so-that-a2-a10/5372/29 "2021-08-16T19:50:08Z")

</div>

**Don’t use the below, NaturalSort.jl is much better**.

> **This is a more robust implementation (and works with bigger numbers):**
>
> ```julia
> function natural_sort!(x::Vector{AbstractString})
> function string_or_number(text)
> if all(isdigit, text)
> val = tryparse(Int, text)
> if val === nothing
> return something(tryparse(BigInt, text), text)
> end
> end
> return text
> end
> 
> function lt(x, y)
> for (a, b) in zip(x, y)
> if !isequal(a, b)
> return lt(a, b)
> end
> end
> return length(x) == length(y)
> end
> lt(x::T, y::T) where T <: Union{Number, AbstractString} = x < y
> lt(x::Number, y::AbstractString) = true
> lt(x::AbstractString, y::Number) = false
> 
> sorter = key -> (string_or_number(m.match) for m in eachmatch(r"[0-9]+|[^0-9]+", key))
> sort!(x, by = sorter, lt = lt)
> end
> 
> ```

[Previous page](https://discourse.julialang.org/t/sorting-strings-containing-numbers-so-that-a2-a10/5372.md?page=1)
