Apples, oranges, *and* bananas

Objective

The last item in a comma-separated list should be prefaced with the word “and” as opposed to a comma.

Example

Convert this:

Front, Garage, Patio, Yard

to this:

Front, Garage, Patio and Yard

Applications

Useful for creating more natural-sounding phrases for speech synthesis. For example:

Front and Garage doors are open.

as opposed to

Front, Garage doors are open.

Method

Paste this into the Template Editor and experiment with it:

{% set doors = 'Front, Garage, Patio, Yard' %}
{{' and '.join(doors.rsplit(', ', 1))}}

Screenshot from 2020-10-11 11-56-12

Real-World Example

This is used to report any doors left open.

{% set pause = '<silence msec="750"/>' %}
{% set qty = states('sensor.all_doors')|int %}
{% set plural = 's' if qty > 1 else '' %}
{% set prep = 'are' if qty > 1 else 'is' %}
Attention! {{pause}} There {{prep}} {{qty}} door{{plural}} left open. 
{{pause}} {{' and '.join(states('sensor.open_doors').rsplit(', ', 1))}} door{{plural}} 
{{pause}} {{prep}} open.

31 Likes

Thumbs up :slight_smile:
Thanks…

Wow! that is so useful in A LOT of announcement automations. Thanks

Damn, son! I mean, DAMN!!! That is awesome!

I beg to differ. Perhaps you might consider the Oxford Comma?

5 Likes

:musical_note:
Check your passport, it’s no trick
Take the Chapstick, put it on your lips
Crack a smile, adjust my tie
Know your butler, unlike other guys
:musical_note:

1 Like

I love it!

But then again, I’m a bit pedantic about language.

Now, if we could only get all those Unix folks to start using upper-case letters once in a while…

Came for the Oxford comma. Leaving satisfied.

Quick and dirty method is to insert a comma here:

', and '

However, that will cause a comma to be used even if there are only two items in the list. To respect the ‘three items or more’ rule would require a slightly more elaborate template. It would use an Oxford comma only if there are three or more items.

It’s not difficult to implement it but would complicate the original example (I wanted to keep it simple).

{% set doors = 'Front, Garage, Patio, Yard' %}
{% set x = ', and ' if doors.split(', ') | count > 2 else ' and ' %}
{{x.join(doors.rsplit(', ', 1))}}

1 Like

ha nice,

will see if this is now defunct:

            {%- set ns = namespace(not_off=[]) %}
            {%- for s in expand('group.iungo_switches_actueel')
              if  s.object_id.split('_actueel')[0] not in
                    ['inductieplaat','patchboard_zolder'] and
                  states(s.entity_id) != '0' and
                  states('switch.' + s.object_id.split('_actueel')[0]) == 'off' %}

            {%- set ns.not_off = ns.not_off + [s.name+ ': ' + s.state + ' watt'] %}
            {%- endfor %}
            {% set count_not_off = ns.not_off|count %}
            {% set list = ns.not_off %}
            {% if count_not_off == 0 %} All fine
            {%- elif count_not_off == 1 %}
                {{list[0]}} is still using power!
            {%- elif count_not_off == 2 %}
                {{list|join(' and ')}} are still using power!
              {%- else %}
                {{list[:-1]|join(', ')}}, and {{list[-1]}} are still using power!
              {%- endif %}

I don’t know how I ended up here after all this time but…

How did you know that rsplit was valid?
It isn’t in the Jinja Template Designer Documenattion which is what the HA Docs point to for templating reference.

I’ve been using split for years in my templates, so long in fact that I have no idea now how I knew that was valid as I just checked and it is also not in the docs.

So cutting to the chase…
(Where) is it documented what is available to use in templates?
Am I missing out on loads of other gems?

Here’s a list of Jinja2’s built-in filters.

You’ll notice that neither split or rsplit are shown and that’s because they are from python. They’re methods of a string.

https://python-reference.readthedocs.io/en/latest/docs/str/split.html

Thanks and yes, but that doesn’t explain how or where we can find out all the possible methods that can be used in HA templates.

Because it doesn’t exist.

Fair enough…

Jinja uses python objects. The only way to know what can be done on an object is to look at the python documentation for said object.

<obj>.function()
   ^
   |
Look this up.

As an FYI, these things will never be documented by HA as the objects could change w/ every python release.

e.g.

"string".rstrip()
   ^
   |
Look this up.

Also, keep in mind, many of the functions may be restricted. I.e. you won’t be able to use them. Like .pop() for a list or any of the _ functions.

1 Like

The added wrinkle is that not everything that is possible in python is supported in Home Assistant’s Jinja2 templates.

On more than one occasion I have found a python example that was impossible to use in a template because it employed something unsupported (the concept of sets comes to mind as well as various list methods). Finding these limitations has been based on trial and error.

FWIW, the technique demonstrated in the first post comes from a python example I found and adapted to what’s permissible in Home Assistant.

1 Like

That’s jinja restricting the objects.

I have been running around trying to look for such a document or reference. Thank you very much for explaining that it doesn’t exist and why. But if ever someone comes across some sort of list of methods that we know (so far) works, that’d be nice to put it here as a comment, so we know what is worth trying.