Jinja: "map" a list to another list (without a loop?)

I’d like to make this cleaner… Using a global with a loop looks ugly to me:

{% set ns = namespace(entities_config=[]) %}

{% for entity_id in entities_ids %}
  {% set ns.entities_config = ns.entities_config + [{
    'entity': entity_id,
    'secondary_info': 'last-changed',
  }] %}
{% endfor %}

{{ ns.entities_config }}

I wish “inline” for expression would work (it doesn’t):

{{ {
    'entity': entity_id,
    'secondary_info': 'last-changed',
} for entity_id in entities_ids }}

Or I was hoping for a map with a closure (doesn’t work):

{{ entities_ids | map(entity_id: {
  'entity': entity_id,
  'secondary_info': 'last-changed',
}) }}

Finally, if no closures, how about a macro (doesn’t work):

{% macro configure_entity(entity_id) %}
  {{ { 
    'entity': entity_id,
    'secondary_info': 'last-changed',
  } }}
{% endmacro %}

# TemplateRuntimeError: No filter named <Macro 'configure_entity'>.
{{ entities
  | map(configure_entity)
  | list 
}}

Well, if there is no such syntax, is there any other way I can get rid of the ugly loop?

Hi DvdNwk,

well, right there you are making a list equal to a list. Just in that case it’s the same list. Change one of the names and see if it works.

Not sure what do you mean. The first example is working. The code you’re quoting (partially: look at the plus sign) is a stupid way to append a value to a list.

The obvious (?) append() function throws an error in HomeAssistant:

And even if it worked, it would output the result of append (which returns None xD) and Expression Statement extension is also not available in HA…

So, in order to append a value, I’m overwriting ns.entities_config var:

Try this:

[{% for x in ['cat', 'bat', 'rat'] %}
{{ dict(animal=x, qty=1) }},
{% endfor %}]

Well, I need to clarify… The goal is to have the result in a var:

{%- set card_config = {
  'type': 'entities',
  'title': area_name(area_id),
  'entities': HERE_I_WANT_THE_MAPPED_OBJECTS,
} -%}

So, in the ideal world it would be something like this:

{%- set card_config = {
  'type': 'entities',
  'title': area_name(area_id),
  'entities': {
    'entity': entity_id,
    'secondary_info': 'last-changed',
  } for entity_id in entities_ids,
} -%}

Since I cannot do “inline for expression” like this, I’m for now stuck with the uglies: “normal for loop”, “global” and “append”:

{%- set ns = namespace(entities_config=[]) -%}

{%- for entity_id in entities_ids -%}
  {%- set ns.entities_config = ns.entities_config + [{
    'entity': entity_id,
    'secondary_info': 'last-changed',
  }] -%}
{%- endfor -%}

{%- set card_config = {
  'type': 'entities',
  'title': area_name(area_id),
  'entities': ns.entities_config,
} -%}

I knew there would be even more requirements …

You’ll have to use what currently exists in Jinja2 (and what Home Assistant’s implementation of it allows).

Yeah, I’m asking if I’m missing something :wink:

Like maybe there is some clever, common way, or maybe I can somehow make the macro way working… Anyway, learning experience, since the original works ofc.

You didn’t miss anything. The original example you posted, using the one and only way to construct a for-loop is how it’s currently done.

Your proposed for-loop syntax is unsupported so no one can post working examples based on fictional syntax. Jinja2 borrows from python but not its “in-place for-loop”.

To my knowledge, the map function cannot be used to transform a list’s string values into a new list with dictionary values so a for-loop is needed.

1 Like