Tony,
* Tony Bowden <[EMAIL PROTECTED]> [2002-07-10 07:01]:
> I was looking for a way to get the first n values from a list, so that
> I could do something like:
>
> [% FOREACH item = mylist.sort('date').first(10) %]
/me nods
> but I couldn't find such a thing... is there a different preferred way
> to do this, or could we change first to something like the following?:
>
> first => sub {
> my $list = shift;
> if (my $howmany = shift) {
> [@{$list}[0 .. $howmany-1]]
> } else {
> $list->[0]
> }
> };
>
> [Or perhaps we need a more generic list.slice mechanism? (Although I'd
> still like the more intuitive list.first(10) than having to say
> list.slice(0..9) or somesuch]
I think a more general splice would be more correct and more generally
useful. Something like
'splice' => sub {
my ($list, $offset, $length, $replace) = @_;
my @newlist = @$list;
my @results;
if (defined $replace) {
@results = splice(@newlist, $offset, $length, $replace)
} elsif (defined $length) {
@results = splice(@newlist, $offset, $length);
} elsif (defined $offset) {
@results = splice(@newlist, $offset);
} else {
@results = splice(@newlist);
}
return \@results;
}
In your example, you'd use it as:
[% FOREACH item = mylist.sort('date').splice(0, 10) %]
Note that I've written it to work on shallow copies of the original
list!
You could create first/last/etc methods in terms of splice:
'first' => sub {
my $list = shift;
my $howmany = shift || 1;
_dotop({}, $list, 'splice', [ 0, $howmany ]);
},
'last' => sub {
my $list = shift;
my $howmany = shift || 1;
_dotop({}, $list, 'splice', [ -$howmany, $howmany ]);
}
Simplistic examples:
$ tpage
[% list = [ 1, 2, 3, 4, 5 ];
"$l " FOREACH l = list.splice(3, 2) %]
4 5
$ tpage
[% list = [ 1, 2, 3, 4, 5 ];
"$l " FOREACH l = list.splice %]
1 2 3 4 5
$ tpage
[% list = [ 1, 2, 3, 4, 5 ];
"$l " FOREACH l = list.splice(3, 0) %]
$ tpage
[% list = [ 1, 2, 3, 4, 5 ];
"$l " FOREACH l = list.first(4) %]
1 2 3 4
$ tpage
[% list = [ 1, 2, 3, 4, 5 ];
"$l " FOREACH l = list.first %]
1
$ tpage
[% list = [ 1, 2, 3, 4, 5 ];
"$l " FOREACH l = list.last(3) %]
3 4 5
And so on. Attached is a diff against the version in CVS (2.64), but
not tests yet. If it's generally useful, we can commit it.
(darren)
--
He who has never configured `sendmail.cf' has no courage. He who has
configured it more than once has no brain.
Index: Stash.pm
===================================================================
RCS file: /template-toolkit/Template2/lib/Template/Stash.pm,v
retrieving revision 2.64
diff -c -w -r2.64 Stash.pm
*** Stash.pm 2002/07/09 14:42:48 2.64
--- Stash.pm 2002/07/12 16:29:42
***************
*** 180,185 ****
--- 180,210 ----
@$list
},
'unique' => sub { my %u; [ grep { ++$u{$_} == 1 } @{$_[0]} ] },
+ 'splice' => sub {
+ my ($list, $offset, $length, $replace) = @_;
+ my @newlist = @$list;
+ my @results;
+ if (defined $replace) {
+ @results = splice(@newlist, $offset, $length, $replace)
+ } elsif (defined $length) {
+ @results = splice(@newlist, $offset, $length);
+ } elsif (defined $offset) {
+ @results = splice(@newlist, $offset);
+ } else {
+ @results = splice(@newlist);
+ }
+ return \@results;
+ },
+ 'first' => sub {
+ my $list = shift;
+ my $howmany = shift || 1;
+ _dotop({}, $list, 'splice', [ 0, $howmany ]);
+ },
+ 'last' => sub {
+ my $list = shift;
+ my $howmany = shift || 1;
+ _dotop({}, $list, 'splice', [ -$howmany, $howmany ]);
+ },
defined $LIST_OPS ? %$LIST_OPS : (),
};