WTH is there no easy way to append/insert text to items in a list in a template

Let’s say I have a list of rooms:

{% set my_list = ["Bedroom", "Dining Room", "Guest Bedroom", ...] %}

And I have a temperature and humidity sensor in each room and I want to get a list of temperature and humidity sensors for each room. Each of those sensor’s has an entity ID like this:

sensor.<room name slugified>_temperature
sensor.<room name slugified>_humidity

To do that, I need to use regex:

{{ my_list | map('slugify') | map('regex_replace', '^(.*)$', 'sensor.\\1_temperature') | list }}
{{ my_list | map('slugify') | map('regex_replace', '^(.*)$', 'sensor.\\1_humidity') | list }}

Or something even more ugly like a for loop with a namespace:

{% set ns = namespace(t=[], h=[]) %}
{% for room in my_list | map('slugify') %}
  {% set ns.t = ns.t + ['sensor.%s_temperature' % room] %}
  {% set ns.h = ns.h + ['sensor.%s_humidity' % room] %}
{% endfor %}
{{ ns.t }}
{{ ns.h }}

Would be nice to have format filter that took the format string as the second argument so this was possible without needing to know how regex and group matches works:

{{ my_list | map('slugify') | map('format', 'sensor.%s_temperature') | list }}
{{ my_list | map('slugify') | map('format', 'sensor.%s_humidity') | list }}

Currently there is a format filter but it takes the format string as the first argument so its not very useful with map.

Or filters that allow you to append and insert text (since formatting can still be pretty technical):

{{ my_list | map('slugify') | map('insert', 'sensor.') | map('append', '_temperature') | list }}
{{ my_list | map('slugify') | map('insert', 'sensor.') | map('append', '_humidity') | list }}

There’s operators for these things when you have a single piece of text but no easy way to do it when you have a list of text.

I don’t know how you can do this without making a different version of format. Maybe call it tamrof because it’ll be backwards.

But then I’m not sure how you pass multiple arguments

EDIT: insert and append would work

{{ my_list | map('slugify') | map('surround', 'sensor.', '_temperature') | list }}
{{ my_list | map('slugify') | map('engulf', 'sensor.', '_temperature') | list }}
{{ my_list | map('slugify') | map('envelop', 'sensor.', '_temperature') | list }}
{{ my_list | map('slugify') | map('immerse', 'sensor.', '_temperature') | list }}
1 Like

Haha yea, the format method would have to be defined a bit bizarrely. Something like this:

def format_for_map(arg1, template, *args, **kwargs):
    """Format in a way that works with map."""
    return template.format(arg1, *args, **kwargs)

As an added bonus could use newer python formatting strings like "For only {price:.2f} dollars!" instead of %s. Or could drop kwargs and do a find and replace of %s with {} and go for consistency with the rest of jinja string formatting if we prefer.

I like surround, engulf, envelop and immerse. I haven’t seen those used in a library for this before but they totally make sense. Plus they sound dramatic to me for some reason :laughing:

1 Like