QGIS Field Calculator Expression – Sorting Alphanumeric Array Numerically

arrayexpressionfield-calculatorqgis

For each street I have a list of house numbers in a column of a CSV file and I need to sort them numerically:

House numbers are separated by -.

name list sorted_list
street A 5/A-5-4-8-3-6-9-7-1-10-7/B-2-7/A 1,2,3,4,5,5/A,6,7,7/A,7/B,8,9,10
street B 15-1-2/AX-2-3 1,2,2/AX,3,15

How can I get the sorted_list column?

I used this expression, but I find it complicated and slow;

array_to_string(
array_foreach(
    array_sort(
        with_variable('lista',
            string_to_array("sorted_list" ,'-'),
            array_foreach(generate_series(0, array_length(@lista)-1),
            lpad(regexp_substr( (@lista[@element]),'(\\d+)'),3,'0')
            ||'|'||
            if(regexp_substr((@lista[@element]),'([a-zA-Z/]+)') !='',
               regexp_substr((@lista[@element]),'([a-zA-Z/]+)'),
               ' ')
            ||'|'||
            @lista[@element]))),
regexp_replace( @element,'^.+\\|(.+)$','\\1'))
)

Is there an easier way to use expressions?


After a few days of study, my request is to obtain the natural sorting as per Kadir's solution, but using the QGIS core expressions; but I think it is impossible and that the way through code is the only and fastest in terms of performance.

Here is a desired example:

solution value
list 1-1/A-10-1r-2/10-10/1A2-10/A-1000/C1-SNC – to order
kadir 1,1/A,1r,2/10,10,10/1A2,10/A,1000/C1,SNC
my SNC,1,1r,1/A,2/10,10,10/1A2,10/A,1000/C1
sort -V 1,1r,1/A,2/10,10,10/1A2,10/A,1000/C1,SNC
sort -n SNC,1,1/A,1r,2/10,10,10/1A2,10/A,1000/C1
natsort 1,1/A,1r,2/10,10,10/1A2,10/A,1000/C1,SNC

sort -V and sort -n are the linux system solutions
natsort is python module and cli to run natural sort processing

Best Answer

Create a new function using Function Editor.

enter image description here

Copy/paste the following script:

from qgis.core import *
from qgis.gui import *
import re

def natural_sort_key(s):
    ns = re.compile('([0-9]+)')
    return [int(t) if t.isdigit() else t.lower() for t in re.split(ns, s)]  

@qgsfunction(args='auto', group='Custom', usesgeometry=False)
def sort_my_addresses(field, feature, parent):
    _list = feature[field].split("-")
    _list.sort(key=natural_sort_key)
     
    return ','.join(_list)

Click on "Save and Load Functions" button. Use this expression:

sort_my_addresses('list')

Note: the field parameter name (list here) for sort_my_addresses should be between single quotes ('), not double quotes ("). For example, 'field_name', not "field_name".

enter image description here

Reference for natural_sort_key method: How to sort a list containing alphanumeric values?

Related Question