Filter or group a collection in Liquid

爷,独闯天下 提交于 2019-12-10 21:31:29

问题


For a simple personal Jekyll blog, I want to group my site.posts by an attribute on post, lang (language). This is either "en", "nl" or nil.

I then want to render two lists of posts. Currently I have:

<section lang="nl">
<h2>Nederlandse Artikelen</h2>
<ul class="posts">
  {% for post in site.posts limit:50 %}
    {% if post.lang == "nl" %}
      {% include li_for_post_with_date.yml %}
    {% endif %}
  {% endfor %}
</ul>
<a href="archief.html">Archief »</a>
</section>
<section lang="en">
<h2>English Articles</h2>
<ul class="posts">
  {% for post in site.posts limit:50 %}
    {% if post.lang == nil or post.lang == "en" %}
      <li><span>{{ post.date | date_to_string }}</span> &raquo; <a href="{{ BASE_PATH }}{{ post.url }}">{{ post.title }}</a></li>
    {% endif %}
  {% endfor %}
</ul>

This has two problems:

  1. Most annoying; when in the last 50 posts, there are 47 lang=en and 3 lang=nl, I now get a skewed list. I would want 25 lang=en and 25 lang=nl entries.
  2. The loop is walked over twice, this strikes me as inneficient.

Is there a way to assign or prepare a collection in Liquid? That way I could loop over site.posts once and prepare a nested collection like site.grouped_posts[en].

Or another trick?

Solution

As Tom Clarkson points out, maintaining a counter is the right direction. However, incrementing a counter has only landed in recent Liquid versions, the one running on Github (where my liquid is compiled) has 2.2.2, without ability to increment a counter. Toms solution itself is not working either, because Liquid turns the variable counter into a string, which cannot be compared with <.

I created a hack, by appending a string and counting the characters.

{% assign counter = '.' %}
{% for post in site.posts %}
  {% if counter.size <= 25 and post.lang == "nl" %}
    {% capture counter %}{{ counter | append:'.' }}{% endcapture %}
    {% include li_for_post_with_date.yml %}
  {% endif %}
{% endfor %}

As said, ugly, so if there are cleaner solutions, please add a solution!


回答1:


I don't think you can create the filtered collection without making a plugin or custom filter, but you may be able to count the number of posts already collected for the group rather than using limit.

{% for post in site.posts %}
    {% if counter < 25 and post.lang == nil or post.lang == "en" %}
        {% capture counter %}{{ counter | plus:1 }}{% endcapture %} 
        <li></li>
    {% endif %}
{% endfor %}

The code is untested, but something fairly similar should work.




回答2:


Unfortunately, Liquid's filters dont't work in for loops. However, they do work in variable assignments.

{% assign posts_by_lang = site.posts | group_by: "lang" %}
{% for lang in posts_by_lang %}
  {{ lang.name }}
  {% for post in lang.items limit: 25 %}
    {{ post.title }}
  {% endfor %}
{% endfor %}

name and items attributes are generated by group_by, the rest is business as usual.



来源:https://stackoverflow.com/questions/13568052/filter-or-group-a-collection-in-liquid

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!