Set operations with List::MoreUtils

[ Perl tips index ]
[ Subscribe to Perl tips ]

In the last Perl tip we briefly mentioned List::MoreUtils. This module (available from the CPAN) provides a wealth of utility methods for working with lists and arrays. Most of these methods are trivial to write for yourself, but have been implemented directly in C so they run as fast as possible even with large lists.

List::MoreUtils provides a great many list operations, but in this tip we'll just examine the most common and easy-to-use set operations. Each of these takes a common form:

        operation { condition } @list

For example:

        # Check to see if any elements are odd

        if ( any { $_ % 2 } @numbers ) {
                print "Some of these elements are odd.\n";
        }
any

any returns true if there is at least one element for which the block returns a true value.

Consider the childhood hangman game. In this game we may wish to compare a single guess against all the letters in the word:

        use List::MoreUtils qw(any);

        # See if they've correctly guessed a letter

        if( any  { $letter eq $_ } split //, $word ) {
                print "$letter is in my word!\n";
                $guesses{$letter}++;
        }
all

all returns true if every element causes the block to return a true value.

For our hangman game, we could use this to see if they've guessed our entire word:

        use List::MoreUtils qw(all);

        # See if they've spelled out the whole word yet

        if( all { exists $guesses{$_} } split //, $word ) {
                print "You have guessed all the letters, well done!\n\n";
                last;
        }
none and part

none returns true if no element causes the block to return a true value, and part allows us to divide a list into those which cause the block to return a false value and those which return a true value.

        use List::MoreUtils qw(none part);

        # Game over.
        # See how many letters they guessed correctly

        if( none { exists $guesses{$_} } split //, $word) {
                print "You didn't guess a single letter correctly!\n";
        }
        else {
                my %word;
                @word{ split //, $word} = ();
                my ($incorrect, $correct) = part { exists $word{$_} } keys %guesses;

                print "You guessed ", scalar(@$correct),
                      " letters correctly (@$correct)\n";

                print "You guessed ", scalar(@$incorrect),
                      " letters incorrectly (@$incorrect)\n";
        }
true and false

If we didn't care which letters were guessed correctly and incorrectly, but instead care just how many letters have been guessed incorrectly we can use false.

        my $wrong_guesses = false { exists $guesses{$_} } split //, $word);

Of course, true does the opposite of false, returning the number of elements that caused our block to return a true value.

There's more!

In addition to the operations described above, List::MoreUtils provides subroutines to allow you to find list indexes or insert elements into parts of your array. You can iterate over multiple arrays, multiple values, zip arrays together, find the minimum and maximum values, and more.

Check out List::MoreUtils for more information.

[ Perl tips index ]
[ Subscribe to Perl tips ]


This Perl tip and associated text is copyright Perl Training Australia. You may freely distribute this text so long as it is distributed in full with this Copyright noticed attached.

If you have any questions please don't hesitate to contact us:

Email: contact@perltraining.com.au
Phone: 03 9354 6001 (Australia)
International: +61 3 9354 6001

Valid XHTML 1.0 Valid CSS