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 : (),
  };

Reply via email to