Help to refine method of finding min & max in an array

I’ve got a Rest sensor that returns a json array of tidal events which I am processing to create various sensors. One of these needs to find the min and max values of one of the attributes. I have worked out how to do it in a for…next loop, but I’m embarassed by how inelegant it is. Can anyone recommend a neater technique?

This is my code:

      - name: "UKtiderange"
        unique_id: "UKtiderange"
        value_template: >
          {% set nsh=namespace(hhigh = 0.0) %} 
          {% set nsl=namespace(lhigh = 9.0) %}
          {% set nshi=namespace(hndx = 0) %} 
          {% set nsli=namespace(lndx = 0) %}
          
          {% for m in range(0, value_json|count - 1) %}
          {% if value_json[m]["EventType"]=="HighWater" %}
          {% if value_json[m]["Height"]|float(0) < nsl.lhigh %}
            {% set nsl.lhigh = value_json[m]["Height"]|float(0) %}
            {% set nsli.lndx = m %}
          {% elif value_json[m]["Height"]|float(0) > nsh.hhigh %}
            {% set nsh.hhigh = value_json[m]["Height"]|float(0) %}
            {% set nshi.hndx = m %}
          {% endif %}
          {% endif %}
          {% endfor %}

which then goes on to do other things which I won’t bore you with. The data looks like this:

[{
  "EventType": "LowWater",
  "DateTime": "2023-10-06T04:18:00",
  "IsApproximateTime": false,
  "Height": 1.5782627259679349,
  "IsApproximateHeight": false,
  "Filtered": false,
  "Date": "2023-10-06T00:00:00"
}, {
  "EventType": "HighWater",
  "DateTime": "2023-10-06T10:05:00",
  "IsApproximateTime": false,
  "Height": 5.4091552062160568,
  "IsApproximateHeight": false,
  "Filtered": false,
  "Date": "2023-10-06T00:00:00"
}, 

etc

{% set hw = value_json | selectattr('EventType', 'eq', 'HighWater')
   | map(attribute='Height') | list }}
{{ hw | min }}
{{ hw | max }}

Does those other things need more than just the maximum and minimum values?

What a neat solution - I’ll try it later. Thank you!
Yes, it computes the daily average tidal range and look for the dip or peak that indicates a Spring or Neap tide event. The sensor captures the event and uses this code to find the time of the corresponding tide.
The entire code from my REST sensor is below - its not efficient so ALL suggestions welcome! I’d wanted to set the date_time of the tide as an attribute but I couldn’t bear repeating the entire code block to do this.

      - name: "UKtiderange"
        unique_id: "UKtiderange"
        value_template: >
          {% set nsh=namespace(hhigh = 0.0) %} 
          {% set nsl=namespace(lhigh = 9.0) %}
          {% set nshi=namespace(hndx = 0) %} 
          {% set nsli=namespace(lndx = 0) %}
          
          {% for m in range(0, value_json|count - 1) %}
          {% if value_json[m]["EventType"]=="HighWater" %}
          {% if value_json[m]["Height"]|float(0) < nsl.lhigh %}
            {% set nsl.lhigh = value_json[m]["Height"]|float(0) %}
            {% set nsli.lndx = m %}
          {% elif value_json[m]["Height"]|float(0) > nsh.hhigh %}
            {% set nsh.hhigh = value_json[m]["Height"]|float(0) %}
            {% set nshi.hndx = m %}
          {% endif %}
          {% endif %}
          {% endfor %}
          
          {% set ns1 = namespace(out="") %}
          {% set ns2 = namespace(range=[]) %}
          {% set ns3 = namespace(event="") %}
          {% set limit = value_json|count - 1  %}
          {% for m in range(0, (value_json|count/4)|round(0)) %}
            {% set n= m|int %}
            {% set this = (value_json[4*n]['Height']|float(0)-value_json[4*n + 1]['Height']|float(0))|abs %}
            {% if 4*n+3 <= limit %}
              {% set this = average(this, (value_json[4*n+2]['Height']|float(0)-value_json[4*n+3]['Height']|float(0))|abs) %}
            {% endif %}
            {% set ns2.range = ns2.range +[this] %}
            {% if n > 0 %}
              {% if ns2.range[n]>=ns2.range[n-1] %}
                {% set change = "+" %}
              {% elif ns2.range[n]<=ns2.range[n-1] %}
                {% set change = "-" %}
              {% else %}
                {% set change = "" %}
              {% endif %}
              {% set ns1.out = ns1.out + change %}
              {% if n>1 %}
                {% if change == "-" and ns1.out[n-2]=="+" %}
                  {% set ns3.event = ns3.event + "Springs /"~value_json[nshi.hndx]["DateTime"] %}
                {% elif change == "+" and ns1.out[n-2]=="-" %}
                  {% set ns3.event = ns3.event + "Neaps /"~value_json[nsli.lndx]["DateTime"] %}
                {% endif %}
              {% endif %}
            {% endif %}
          {% endfor %}    
          {{ ns3.event }}           

Just tried that & it does what you said, finds min/max. My question was not well framed. How do I find the corresponding times (as per my code)?

{% set hw = value_json | selectattr('EventType', 'eq', 'HighWater')
   | map(attribute='Height') | list }}
{{ hw | min }}
{{ hw | max }}

{{ value_json | selectattr('EventType', 'eq', 'HighWater')
   | selectattr('Height', 'eq', hw | min | float(0))
   | map(attribute='DateTime') | list | first }}

{{ value_json | selectattr('EventType', 'eq', 'HighWater')
   | selectattr('Height', 'eq', hw | max | float(0))
   | map(attribute='DateTime') | list | first }}

Brilliant, thank you. That map looks very useful, I’ll have to read up on it.

Jinja2: map

EXAMPLE

{% set value_json = [
  { "animal": "cat", "qty": 3},
  { "animal": "dog", "qty": 2},
  { "animal": "bird", "qty": 12}
] %}

{{ value_json | map(attribute='animal') | list }}
{{ value_json | map(attribute='qty') | list }}