Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Re: Efficiently finding values of an extremity

by ikegami (Patriarch)
on Jul 20, 2005 at 18:48 UTC ( [id://476589]=note: print w/replies, xml ) Need Help??


in reply to Efficiently finding values of an extremity

tye suggested that minima be added to List::Util. It looks something like this. Of course, his minima was probably terser/cleaner :)

sub minima(&@) { my $value = shift(@_); my @matches; my $min_val; { local $_ = shift(@_); $min_val = &$value(); @matches = $_; } foreach (@_) { my $val = &$value(); if ($val == $min_val) { push(@matches, $_); } elsif ($val < $min_val) { $min_val = $val; @matches = $_; } } return @matches; }

If so, the original question can be solved with:

use List::Util qw( minima maxstr ); my $val = maxstr minima { length } @list;

and the bonus question can be solved with:

use List::Util qw( minima ); sub pick { $_[rand(@_)] } my $val = pick minima { length } @list;

Replies are listed 'Best First'.
Re^2: Efficiently finding values of an extremity (tye's)
by tye (Sage) on Jul 20, 2005 at 19:12 UTC

    This is what I threw on my scratchpad, plus two bug fixes:

    sub maxima(&@) { my $measure = shift @_; return if ! @_; my @maxima = shift @_; my $max; $max = $measure->( $_ ) for @maxima; for( @_ ) { my $key = $measure->( $_ ); if( $max < $key ) { @maxima = $_; $max = $key; } elsif( $max == $key ) { push @maxima, $_; } } return @maxima; } sub minima(&@) { my $measure = shift @_; return if ! @_; my @minima = shift @_; my $min; $min = $measure->( $_ ) for @minima; for( @_ ) { my $key = $measure->( $_ ); if( $key < $min ) { $min = $key; @minima = $_; } elsif( $key == $min ) { push @minima, $_; } } return @minima; } sub strmaxima(&@) { my $measure = shift @_; return if ! @_; my @maxima = shift @_; my $max; $max = $measure->( $_ ) for @maxima; for( @_ ) { my $key = $measure->( $_ ); if( $max lt $key ) { @maxima = $_; $max = $key; } elsif( $max eq $key ) { push @maxima, $_; } } return @maxima; } sub strminima(&@) { my $measure = shift @_; return if ! @_; my @minima = shift @_; my $min; $min = $measure->( $_ ) for @minima; for( @_ ) { my $key = $measure->( $_ ); if( $key lt $min ) { @minima = $_; $min = $key; } elsif( $key eq $min ) { push @minima, $_; } } return @minima; }

    Which I think would be fine additions to List::Util.

    However, (Update: I added return   if  ! @_; to each because ) these should return an empty list not (undef) when given an empty list.

    - tye        

      I've always known these (at least in their single-valued incarnations) as argmin & argmax, and I've even seen them used with those names in mathematical literature. I would prefer a naming scheme where the "arg-" prefix indicates that we return the index/indices which induced the extremal value(s) (and not the extremal value(s) itself/themselves), and the "-ima" suffix indicates that we return multiple values when there is a tie.

      It never occurred to me that a plural version of them might be useful, but I don't see why not. Perhaps the two optimized cases could even be combined efficiently by checking wantarray.

      Whatever you want to call it, I'm with you in that I've always wanted functions like these included in List::Util.

      blokhead

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://476589]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (6)
As of 2024-04-19 10:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found