HubL - 配列(リスト)、連想配列(ディクショナリ)に関わる処理まとめ
本ページではHubLのリストとディクショナリの扱いについてまとめます。呼称については「リスト」がドキュメント内の呼称ではありますが、「リスト」という単語はCRMの機能にも存在し紛らわしいため、本ページでは配列と称します。
追加 / 削除
ディクショナリに要素を追加する:update
{%- set dict = { first_name: 'atsushi', last_name: 'handa' } -%} {%- do dict.update({height: 180, skill: 'HubSpot CMS'}) -%} {{ dict }}
出力
{first_name=atsushi, last_name=handa, height=180, skill=HubSpot CMS}
末尾に要素を追加する:append
{%- set list = ['hoge', 'fuga'] -%} {%- do list.append('piyo') -%} {{ list }}
出力
[hoge, fuga, piyo]
ループやifのブロック内からも更新可能
{%- set list = ['hoge', 'fuga'] -%} {%- for item in range(2) -%} {%- do list.append('from loop' + loop.index) -%} {%- endfor -%} {%- if true -%} {%- do list.append('from if') -%} {%- endif -%} {{ list }}
出力
[hoge, fuga, from loop1, from loop2, from if]
指定のインデックスに要素を追加する:insert
{%- set list = ['hoge', 'fuga'] -%} {%- do list.insert(1, 'piyo') -%} {{ list }}
出力
[hoge, piyo, fuga]
指定のインデックスの要素を削除する:pop
{%- set list = ['hoge', 'fuga', 'piyo'] -%} {%- do list.pop(0) -%} {{ list }}
出力
[fuga, piyo]
削除した要素を取得/出力することもできる
取得する場合
{%- set list = ['hoge', 'fuga', 'piyo'] -%} {%- set poped_item = list.pop(0) -%} {{ poped_item }} {{ list }}
出力
hoge [fuga, piyo]
そのまま出力する場合
{%- set list = ['hoge', 'fuga', 'piyo'] -%} {{ list.pop(0) }} {{ list }}
出力
hoge [fuga, piyo]
全ての要素を削除する:clear
{%- set list = ['hoge', 'fuga', 'piyo'] -%} {%- do list.clear() -%} {{ list }}
出力
[]
ディクショナリもOK
取得
要素数を取得する:length
{%- set list = ['hoge', 'fuga', 'piyo'] -%} {{ list|length }}
出力
3
要素のインデックスを取得する:index
見つからない場合は-1が返る
{%- set list = ['hoge', 'fuga', 'piyo'] -%} {{ list.index('piyo') }} {{ list.index('hego') }}
出力
2 -1
最初の要素を取得する:first
{%- set list = ['hoge', 'fuga', 'piyo'] -%} {{ list|first }}
出力
hoge
最後の要素を取得する:last
{%- set list = ['hoge', 'fuga', 'piyo'] -%} {{ list|last }}
出力
piyo
ランダムに1件取得する:random
{%- set list = ['hoge', 'fuga', 'piyo', 'foo', 'bar', 'baz'] -%} {{ list|random }} {{ list|random }}
出力
baz piyo
ただし、サーバーサイドのページキャッシュを破棄する訳ではないため、ページリロード毎に必ずランダムに出力が必要な場合はJavaScriptの利用を推奨とのこと。
要素の出現数をカウントする:count
{%- set list = ['hoge', 'fug', 'piyo', 'hoge'] -%} {{ list.count('hoge') }}
出力
2
変更を加える、配列に対して何らかの処理を行う
ランダムにする:shuffle
{%- set list = ['hoge', 'fuga', 'piyo', 'foo', 'bar', 'baz'] -%} {{ list|shuffle }} {{ list|shuffle }}
出力
[hoge, fuga, baz, bar, piyo, foo] [hoge, piyo, foo, bar, fuga, baz]
合計する:sum
{%- set num_list = [1, 2, 3, 4, 5] -%} {{ num_list|sum }}
出力
15
一括処理を適用する:map
単純なフィルタの適用
{%- set list = ['piyo', 'foo', 'bar'] -%} {{ list|map('upper') }}
出力
[PIYO, FOO, BAR]
配列内のディクショナリが持つ属性を指定して処理を行う場合
{%- set rec_posts = [ { name: 'post 1', absolute_url: '/post_1/', topic_list: ['hoge', 'fuga'] }, { name: 'post 2', absolute_url: '/post_2/', topic_list: ['foo', 'bar'] } ] -%} {{ rec_posts|map(attribute='topic_list')|join(', ') }}
出力
[hoge, fuga], [foo, bar]
逆順にする:reverse
{%- set list = ['hoge', 'fuga', 'piyo'] -%} {%- do list.reverse() -%} {{ list }}
出力
[piyo, fuga, hoge]
ループで回す際はフィルタも利用可能
{%- set list = ['hoge', 'fuga', 'piyo'] -%} {%- for item in list|reverse -%} {{ item }}, {%- endfor -%}
出力
piyo,fuga,hoge,
重複を解消する:unique
{%- set list = ['hoge', 'fuga', 'piyo', 'hoge'] -%} {{ list|unique }}
出力
[hoge, fuga, piyo]
フィルタする
Expression testsと肯定系で評価するフィルタ:select
{%- set list = ['hoge', 'fuga', 'piyo', 1, 2] -%} {{ list|select('number') }}
出力
[1, 2]
Expression testsと否定系で評価するフィルタ:reject
{%- set list = ['hoge', 'fuga', 'piyo', 1, 2] -%} {{ list|reject('number') }}
出力
[hoge, fuga, piyo]
配列内のディクショナリの属性の有無でフィルタ:select_attr
第二引数にExpression Tests、第三引数にExpression Testsで使用する値を入れてさらにフィルタすることも可能
{%- set rec_posts = [ { name: 'hoge', absolute_url: '/hoge/', img: { src: 'hoge' } }, { name: 'fuga', absolute_url: '/fuga/', img: { src: 'fuga' } }, { name: 'piyo', absolute_url: '/piyo/' } ] -%} {{ rec_posts|selectattr('img.src') }} {{ rec_posts|selectattr('img.src', 'string_containing', 'fuga') }}
出力
[{name=hoge, absolute_url=/hoge/, img={src=hoge}}, {name=fuga, absolute_url=/fuga/, img={src=fuga}}] [{name=fuga, absolute_url=/fuga/, img={src=fuga}}]
ソートする:sort
配列内のディクショナリの属性名を第三引数に渡し、ソートするのが基本
{%- set rec_posts = [ { name: 'hoge', absolute_url: '/hoge/', img: { src: 'hoge' } }, { name: 'fuga', absolute_url: '/fuga/', img: { src: 'fuga' } }, { name: 'piyo', absolute_url: '/piyo/' } ] -%} {{ rec_posts|sort(false, false, 'name') }}
出力
[{name=fuga, absolute_url=/fuga/, img={src=fuga}}, {name=hoge, absolute_url=/hoge/, img={src=hoge}}, {name=piyo, absolute_url=/piyo/}]
ただし引数を渡さないと、単純な配列もソートできる
{{ [1,3,2,7,5]|sort() }} {{ ['c', 'd', 'a', 'b']|sort() }}
出力
[1, 2, 3, 5, 7] [a, b, c, d]
ディクショナリをソートする:dictsort
{%- set dict = { skill: 'HubSpot CMS', first_name: 'atsushi', last_name: 'handa', height: 180 } -%} {{ dict|dictsort(false, 'value') }}
出力
{%- set dict = { skill: 'HubSpot CMS', first_name: 'atsushi', last_name: 'handa', height: 180 } -%} {{ dict|dictsort(false, 'value') }}
2つ以上の配列を扱う
配列を結合する:extend
重複があっても気にしない形
{%- set first = [1, 2, 3] -%} {%- set second = [3, 4, 5] -%} {%- do first.extend(second) -%}
出力
[1, 2, 3, 3, 4, 5]
配列をマージする:union
重複なし
{%- set first = [1, 2, 3] -%} {%- set second = [3, 4, 5] -%} {{ first|union(second) }}
出力
[1, 2, 3, 4, 5]
コピーする:copy
参照ではなく、きちんと値をコピーしていることがわかる
{%- set original_list = [ 'hoge', 'fuga', [ 'foo', 'bar' ], [ { name: 'post 1', absolute_url: '/post_1/' }, { name: 'post 2', absolute_url: '/post_2/' } ] ] -%} {%- set cloned_list = original_list.copy() -%} {%- do original_list.append('after copy1') -%}
出力
original_list: [hoge, fuga, [foo, bar], [{name=post 1, absolute_url=/post_1/}, {name=post 2, absolute_url=/post_2/}], after copy1] cloned_list: [hoge, fuga, [foo, bar], [{name=post 1, absolute_url=/post_1/}, {name=post 2, absolute_url=/post_2/}]]
2つの配列のうち、1つ目にしかない要素から新しい配列を作る:difference
{%- set list1 = ['hoge', 'fuga', 'piyo'] -%} {%- set list2 = ['piyo', 'foo', 'bar'] -%} {{ list1|difference(list2) }}
出力
[hoge, fuga]
2つの配列の共通から新しい配列を作る:intersect
{%- set list1 = ['hoge', 'fuga', 'piyo'] -%} {%- set list2 = ['piyo', 'foo', 'bar'] -%} {{ list1|intersect(list2) }}
出力
[piyo]
2つの配列の共通しない要素から新しい配列を作る:symmetric_difference
{%- set list1 = ['hoge', 'fuga', 'piyo'] -%} {%- set list2 = ['piyo', 'foo', 'bar'] -%} {{ list1|symmetric_difference(list2) }}
出力
[hoge, fuga, foo, bar]
ループにまつわる処理
ループ内で使用できる予約変数についてはこちら Loop properties
任意の回数ループする:range
{%- for item in range(3) -%} loop {{ item }}, {%- endfor -%}
出力
loop 0,loop 1,loop 2,
ディクショナリをループする:items
{%- set dict = { first_name: 'atsushi', last_name: 'handa' } -%} {%- for key, val in dict.items() -%} {{ key }}: {{ val }}, {%- endfor -%}
出力
first_name: atsushi,last_name: handa,
配列をループ内で分割する:batch、slice
batchとsliceの挙動はほぼ同じように思えるが……。
batch
{%- set list = ['hoge', 'fuga', 'piyo', 'foo', 'bar'] -%} {%- for batched in list|batch(2, 'null') %} <p> {%- for item in batched -%} {{ item }}, {%- endfor -%} </p> {%- endfor -%}
出力
<p>hoge,fuga,</p> <p>piyo,foo,</p> <p>bar, ,</p>
slice
{%- set list = ['hoge', 'fuga', 'piyo', 'foo', 'bar'] -%} {%- for sliced in list|slice(2, 'null') %} <p> {%- for item in sliced -%} {{- item -}}, {%- endfor -%} </p> {%- endfor -%}
出力
<p>hoge,fuga,</p> <p>piyo,foo,</p> <p>bar, ,</p>
配列内のディクショナリの任意の属性でグループ化する:groupby
{%- set rec_posts = [ { name: 'post 1', absolute_url: '/post_1/', publish_date: '2020/02' }, { name: 'post 2', absolute_url: '/post_2/', publish_date: '2020/02' }, { name: 'post 2', absolute_url: '/post_2/', publish_date: '2020/01' } ] -%} <dl> {%- for group in rec_posts|groupby('publish_date') -%} <dt>公開日が{{ group.grouper }}の記事</dt> {%- for rec_post in group.list -%} <dd>{{ rec_post.name }}</dd> {%- endfor -%} {%- endfor -%} </dl>
出力
<dl> <dt>公開日が2020/02の記事</dt> <dd>post 1</dd> <dd>post 2</dd> <dt>公開日が2020/01の記事</dt> <dd>post 2</dd> </dl>