duskwuff already explains in their answer 您不能将对象用作哈希键,因为它们会被序列化,您将失去对象性。我的答案就是基于此。
假设您有一个数组数组,其中每个内部数组包含一对对象。我创建了 Moo 类来说明。
package My::Model::Group;
use Moo;
has [qw/id name/] => ( is => 'ro' );
package My::Model::Group::Admin;
use Moo;
has [qw/id name/] => ( is => 'ro' );
package main;
my $groups = [
[
My::Model::Group->new( id => 1, name => 'group1' ) =>
My::Model::Group::Admin->new( id => 1, name => 'foo' )
],
[
My::Model::Group->new( id => 2, name => 'group2' ) =>
My::Model::Group::Admin->new( id => 1, name => 'foo' )
],
[
My::Model::Group->new( id => 3, name => 'group3' ) =>
My::Model::Group::Admin->new( id => 1, name => 'bar' )
],
[
My::Model::Group->new( id => 4, name => 'group4' ) =>
My::Model::Group::Admin->new( id => 1, name => 'foo' )
],
];
有四对。两个管理员,四个组。其中三个组属于 foo 管理员,一个属于 bar。现在让我们看一下模板。
use Template;
my $tt = Template->new();
$tt->process( \*DATA, { groups => $groups }, \my $output )
or die $tt->error;
print $output;
__DATA__
[%- FOREACH item IN groups -%]
[%- DEFAULT by_admin.${item.1.name} = [] -%]
[%- by_admin.${item.1.name}.push(item.0) -%]
[%- END -%]
[%- FOREACH admin IN by_admin.keys.sort -%]
[%- FOREACH group IN by_admin.$admin -%]
[%- admin %] -> [% group.id %]
[%- END -%]
[%- END -%]
相关部分显然是DATA 部分。我们需要将数组数据结构重新组织成一个包含管理员的哈希,然后将每个组排序到一个管理员槽中。
我们不需要创建by_admin 变量。它将被隐式全局创建。但是我们确实需要为$by_admin->{$item[0]->name} 设置一个默认值(我现在使用Perl 语法,以便于理解)。 Template Toolkit 似乎不知道autovivification,而the DEFAULT keyword 与//= assignment operator in Perl 类似。
然后我们可以将push 的第一个元素item 放入我们刚刚在哈希引用元素中创建的数组引用中(如果它还不存在的话),键为item.1.name 在by_name 内。
一旦我们完成准备,剩下的只是一个简单的循环。我们迭代 by_admin 的 sorted keys,然后迭代该键后面的数组 ref。
这是输出:
bar -> 3
foo -> 1
foo -> 2
foo -> 4
最好不要在模板中而是在控制器中进行预处理。作为普通的 Perl 代码,它应该更容易阅读。
my %by_admin;
for my $group (@$groups) {
push @{ $by_admin{ $group->[1]{name} } }, $group->[0];
}
请注意,为简洁起见,我省略了 use strict 和 use warnings。