Jinja2 Sorting on Multiple Attributes in Different Orders

I’m attempting to sort in jinja2 on multiple attributes in different orders.
In this example, I’d like the ordering to be START in acsending order, and END in descending order.

I have created this test template in HA to test the results:

{% set data = [
  {"name": "First", "start": "00:00", "end": "01:00"},
  {"name": "Second", "start": "01:00", "end": "03:00"},
  {"name": "Third", "start": "00:00", "end": "02:00"}
] %}

{% set mylist = data | sort(attribute='start', reverse=false) | sort(attribute='end', reverse=true) | list %}

{{mylist}}

The results are:

[
  {
    "name": "Second",
    "start": "01:00",
    "end": "03:00"
  },
  {
    "name": "Third",
    "start": "00:00",
    "end": "02:00"
  },
  {
    "name": "First",
    "start": "00:00",
    "end": "01:00"
  }
]

It has only ordered by END descending
I would like the final order to be:

Third
First
Second

In SQL it would be as simple as:

ORDER BY start ASC, end DESC

Any ideas? Thanks.

1 Like

Smells like a bug.
The jinja2 documentation explicitely says this should work:

https://jinja.palletsprojects.com/en/2.11.x/templates/#sort

You need to change the order of your sorts, so that the secondary sort is first in your list, like so:

{% set mylist = data | sort(attribute='end', reverse=true) | sort(attribute='start', reverse=false) | list %}

Semantically, this says to sort end reversed, so that when you come along next and sort by start, if there are any ties in the sorting of start, the sorting of end will be preserved.

Thanks for the response, really appreciate it.

I can’t for the life of me understand why it doesn’t work the other way around, it’s essentially the same thing.
It says to sort ‘start’ ascending, so that when you come along and sort by ‘end’, if there are any ties in the sorting of ‘end’, the sorting of ‘start’ will be preserved.

If that’s not the case, I get the feeling with different test data, it’s going to fail again and produce the wrong results in the other direction. Unless, as Koying says, it smells like a bug.

1 Like

I understand why this is confusing, and I don’t think I did a very good job explaining.

The first thing to know is that the sort filter doesn’t support compound sorting the way you think of it as in your SQL example. You can get the same result by taking advantage of the “stable” nature of the sort filter though (meaning that when there are ties, it leaves the elements in the original order).

Let’s go step by step. From the computer’s perspective, in your original template you ask it to sort by start first. It does that The new list is now sorted [Third, First, Second]. Second is last because it has the “highest” end time, lexicographically. Third is before First because that’s the way they were ordered in the original list.

Then you ask it to sort that new list by end next. There are no ties in end, so the new list is [Second, Third, First], a list sorted “only” by end, as you say.

What we’re seeing here is that the sort that happens last will have the effect of being the primary sort. So, instead, let’s first ask it to sort by end. Now we get [Second, Third, First] because “03:00” > “02:00” > “01:00”.

Now we can ask it to sort the list that results from that by start. This time we get [Third, First, Second] because Third’s “00:00” is equal to First’s “00:00” (but we already sorted them by end descending, so these two elements will be in the right order) and Second is after them because “00:00” < “01:00”.

1 Like

Thanks, there isn’t very much on this site for Templating Jinja2 Sorting, and this is by far the best explanation.