How to exclude comma in last item in for loop that is prefaced by if condition (and output valid JSON)


#1

I have a for loop prefaced by an if condition like this:

{
{% for item in site.posts %}
    {% if item.special %} 
            "{{ item.content }}"{% unless forloop.last %},{% endunless %}
     {% endif %}
{% endfor %}
}

The output format needs to be JSON, so the end result should have an object with comma-separated strings, like this:

{
    "first item",
    "second item",
    "third item"
}

However, the forloop seems to calculate based the length of all potential items in site.posts, not just those items that meet my if condition. When I preface it with the if condition, fewer items get iterated through. As a result, the forloop.last doesn’t accurately omit the comma before the last item in the loop. How do I overcome this so that my JSON is valid and doesn’t end up invalid like this?

{
    "first item",
    "second item",
    "third item",
}

#2

could you do an assign instead, and then loop thru that?

`{% assign special_items = site.posts | where: “special”,“true” %}

no idea if that is possible, just an idea.


#3

What if you did something like this with push to add the content of any items that match special to a new (or existing array). Then you can output that variable and filter it with jsonify.

// initializes an empty array to push to
{% assign my_array = "" | split: ", " %}

{% for item in site.posts %}
  {% if item.special %}
    {% assign my_array = my_array | push: item.content %}
   {% endif %}
{% endfor %}

{{ my_array | jsonify }}

#4

@rdyar That approach would normally work, but my actual scenario is a little more complex and I couldn’t quite wrangle the logic to work there. But thanks for responding.

@mmistakes Wow, this code actually works! Thank you. I realize I didn’t include a lot of details here, but you nailed it with what I needed.

In case anyone is interested, here’s the full code of the feed I was working on. The recommendations element has the code that mmistakes suggested:

---
layout: null
---

[
  {% for ep in site.posts %}
  {
    "id": "{{ep.guid}}",
    "title": "{{ep.title}}",
    "description": "{{ep.summary}}",
    "duration": "{{ep.podcast_duration}}",
    "thumbURL": "{{site.url}}/{{ep.mp4_thumbnail | escape}}",
    "imgURL": "{{site.url}}/{{ep.mp4_thumbnail | escape}}",
    "videoURL": "{{ep.mp4_url}}",
    "categories": [
      "{{ep.meetup}}"
    ],
    "channel_id": "{{ep.categories}}",
    "recommendations":
     {% assign my_array = "" | split: ", " %}

     {% for tag in ep.tags %}
     {% for mypost in site.tags[tag] %}
     {% if mypost.url != ep.url %}
    {% assign my_array = my_array | push: {{mypost.guid}} %}
    {% endif %}
  {% endfor %}
{% endfor %}

{{my_array | jsonify}}

  } {% unless forloop.last %},{% endunless %}
{% endfor %},
{
"globalRecommendations": [
  {% assign globalRecs = site.posts | where: "global_recommendation", true %}
{% for ep in globalRecs %}
  "{{ ep.guid }}"{% unless forloop.last %},{% endunless %}
  {% endfor %}
]
}
]

This feed is used in a Fire TV app. I am generating recommended videos based on tags. Each post has a tag. The recommendations should include other videos that also have this tag, but not the video itself (which has the tag). You can see the result here: http://podcast.writethedocs.org/fab.json.

For example, in that feed link, the first title, WTD Episode 4, has the tag “docs-as-code”. The recommendations property includes other titles (the guid’s of those titles) that also have this same docs-as-code tag:

"recommendations": [
"wtdpodcast_ep3_docsascode",
"modern_tech_writing"
]

But as desired, WTD Episode 4 is not included in those recommendations.

(I imagine a similar technique could be used for related posts on a blog, though I’m guessing the build time would be considerable with a large number of items.)

Thanks again.


#5

For people wanting to exclude the final comma from an array in your template, you could first build an array and then use array_to_sentence_string to modify the final connecting term. Like:

{{my_array | array_to_sentence_string: '' }}

By default, array_to_sentence_string uses and as the last connecting term (like: one, two and three) but as of Jekyll 3.4 it can accept a parameter for the final connecting term.

For example:

{{ page.tags | array_to_sentence_string: 'or' }}

Will output:

one, two, or three

@desiredpersona wrote about this on our blog here: