VladoPortos
VladoPortos

Reputation: 603

Sorting list in Ansible in natural alphanumeric order

Is there a way to sort a list in Ansible or Jinja in a natural way?

For example this is the list

test
test123
test12
test5
test1234test
test22te

And I need it to take in account the numbers as whole not as individual so test12 is under test5 and so on.

Upvotes: 2

Views: 1915

Answers (2)

Vladimir Botka
Vladimir Botka

Reputation: 68044

Given the list

  l1:
    - test
    - test123
    - test12
    - test5
    - test1234test
    - test22te

Create a list with an attribute index of type integer, e.g.

    - set_fact:
        l2: "{{ l2|default([]) +
                [{'index': (_index|length > 0)|ternary(_index|int, 0),
                  'name': item}] }}"
      loop: "{{ l1 }}"
      vars:
        _regex: '^test(\d*)\D*$'
        _replace: '\1'
        _index: "{{ item|regex_replace(_regex, _replace) }}"
    - debug:
        msg: "{{ l2|sort(attribute='index')|
                    map(attribute='name')|
                    list }}"

gives

  msg:
  - test
  - test5
  - test12
  - test22te
  - test123
  - test1234test

Without iteration, declare the variables

  _regex: '^test(\d*)\D*$'
  _replace: '\1'
  _index: "{{ l1|map('regex_replace', _regex, _replace)|map('int')|list }}"
  l2: "{{ dict(_index|zip(l1))|
                      dict2items|
                      sort(attribute='key')|
                      map(attribute='value')|
                      list }}"

gives the same result

  l2:
  - test
  - test5
  - test12
  - test22te
  - test123
  - test1234test

Example of a complete playbook for testing

- hosts: localhost

  vars:

    l1:
      - test
      - test123
      - test12
      - test5
      - test1234test
      - test22te

    _regex: '^test(\d*)\D*$'
    _replace: '\1'
    _index: "{{ l1|map('regex_replace', _regex, _replace)|map('int')|list }}"
    l2: "{{ dict(_index|zip(l1))|
                        dict2items|
                        sort(attribute='key')|
                        map(attribute='value')|
                        list }}"

  tasks:

    - debug:
        var: _index
    - debug:
        var: l2

Upvotes: 2

VladoPortos
VladoPortos

Reputation: 603

In the end made jinja filter "natsort_filter.py" that does what I need. Get it here if you like:

https://gitlab.privatecloud.sk/vladoportos/custom-jinja-filters

It does require natsort module for python, but than it works just fine :)

Upvotes: 0

Related Questions