Reputation: 8240
My understanding is that Liquid converts Ruby Hashes to arrays for use in tags. For example, when using Jekyll:
{% for category in site.categories %}
<li>{{ category[0] }}</li>
{% endfor %}
... converts site.categories to an array of tuples in which [0] refers to the key, [1] the list of values.
If I wanted the above category map to be sorted alphabetically by the key ([0] of each tuple) how can I do this?
Upvotes: 12
Views: 7744
Reputation: 1870
You can sort by the key using the following method (that is compatible with Github Pages):
{% assign sorted_categories = (site.categories | sort:0) %}
{% for category in sorted_categories %}
<!-- Using the 'capitalize' filter in Liquid Tags - you can leave this out -->
<li>{{category[0] | capitalize }}</li>
{% assign sorted_catposts = (category[1] | sort: 'title', 'last') %}
{% for catpost in sorted_catposts %}
<!-- The posts within each category are now alphabetically sorted by title -->
<!-- Do stuff with each post in each category -->
{% endfor %}
{% endfor %}
Hope this helps.
Upvotes: 3
Reputation: 24314
You could save yourself some trouble and extend Liquid
:
e.g.
# https://gist.github.com/dnozay/026862f5d65dcb8b4353
module Jekyll
module Toolbox
def keys(hash)
hash.keys
end
def to_ul(collection)
result = ''
collection.each do |item|
result << "<li>#{item}</li>"
end
result
end
end
end
Liquid::Template.register_filter(Jekyll::Toolbox)
Usage:
{{ myhash | keys | to_ul }}
Examples:
# https://gist.github.com/dnozay/026862f5d65dcb8b4353
@context = { 'myhash' => { 'b' => 'B', 'a' => 'A', 'c' => 'C' } }
@template = Liquid::Template.parse("{{ myhash | keys | to_ul }}")
@template.render(@context) # => "<li>b</li><li>a</li><li>c</li>"
@template = Liquid::Template.parse("{{ myhash | keys | sort | to_ul }}")
@template.render(@context) # => "<li>a</li><li>b</li><li>c</li>"
If you feel lucky you can look on github for the for.rb
file and extend the for
syntax to handle hashes better :).
Upvotes: 2
Reputation: 5471
{% capture tags %}
{% for tag in site.tags %}
{{ tag[0] }}
{% endfor %}
{% endcapture %}
{% assign sortedtags = tags | split:' ' | sort %}
{% for tag in sortedtags %}
<h4>#{{ tag }}</h4>
<ul>
{% for post in site.tags[tag] %}
<li>
<span>{{ post.date | date_to_string }}</span>
<a href="{{ post.url }}">{{ post.title }}</a>
</li>
{% endfor %}
</ul>
{% endfor %}
Upvotes: 4
Reputation: 1841
I also want to be part of this obfuscated competition (dudes, number_of_words
, seriously?).
This code is building the list tag by tag, looking for the next tag in lexicographic order in the list at each step. It's in O(n²) where n is the number of tags.
<section>
<h1>Pick a tag!</h1>
<ul id="recent_posts">
{% assign current_tag = ' ' %}
{% for t in site.categories %}
<li class="post">
{% assign next_tag = 'ZZZ' %}
{% for item in site.categories %}
{% assign tag = item.first %}
{% if tag > current_tag and tag < next_tag %}
{% assign next_tag = tag %}
{% endif %}
{% endfor %}
{{ next_tag | category_link }} {{ site.categories[next_tag].size }}
{% assign current_tag = next_tag %}
</li>
{% endfor %}
</ul>
</section>
BTW, Liquid comments look absurdly heavy.
Upvotes: 1
Reputation: 2800
You can also use arrays instead of hashes!
Instead of using this yaml:
categories:
a_category: category description
another_category: another category description
You can use this one:
categories:
- {name: 'a category', description: 'category description'}
- {name: 'another category', description: 'another category description'}
And then you can iterate like this, and order will be preserved :)
{% for category in site.categories %}
<li>{{ category['name'] }}</li>
{% endfor %}
Upvotes: 8
Reputation: 69
Here's how I fixed Nikos problem:
{% capture get_items %}
{% for cat in site.categories %}
{{ cat | first | replace: ' ', '_' }}
{% endfor %}
{% endcapture %}
{% capture num_words %}
{{ get_items | split:' ' | sort | join:' ' | number_of_words }}
{% endcapture %}
{% for item in (1..num_words) %}
<li>{{ get_items | split:' ' | sort | join:' ' | truncatewords:item | remove:'...' | split:' ' | last | replace: '_', ' ' }}</li>
{% endfor %}
Now how to get this working with HAML...
Upvotes: 0
Reputation: 109
This is an old question, but I just spend the last little while figuring this out for myself. I used the following code to achieve what you ( and I ) wanted.
{% capture get_items %}
{% for cat in site.categories %}
{{ cat | first }}
{% endfor %}
{% endcapture %}
{% capture num_words %}
{{ get_items | split:' ' | sort | join:' ' | number_of_words }}
{% endcapture %}
{% for item in (1..num_words) %}
<li>{{ get_items | split:' ' | sort | join:' ' | truncatewords:item | remove:'. ..' | split:' ' | last }}</li>
{% endfor %}
Upvotes: 9
Reputation: 52651
Neither the default Liquid implementation nor the additions made by Jekyll allow for what you want.
I'm afraid what you want is simply not possible with the current setup. You would have to monkeypatch Jekyll or Liquid in order to make the hashes return their keys in a sorted order.
Upvotes: 1