Perl 101: Things Every Perl Programmer Should Know.

Arrays & Lists

Arrays of words are easily created

The qw operator makes creating arrays easy. It means "quote on whitespace into a list":

    # Perl 5
    my @stooges = qw( Larry Curly Moe Iggy );
    # or
    my @stooges = qw(
        Larry
        Curly
        Moe
        Iggy
    );

In Perl 6, the qw is simplified:

    my @stooges = < Larry Curly Moe Iggy >;
    # or
    my @stooges = <
        Larry
        Curly
        Moe
        Iggy
    >;

The elements do not interpolate, so:

    my @array = qw( $100,000 ); # Perl 5
    my @array = < $100,000 >;   # Perl 6

The single element of @array is '$100,000'.

Access arrays with numeric values

To get a single scalar out of an array, access it with the [] and a $ sigil. All arrays in Perl start at 0.

    $stooges[1] # Curly

Arrays can also be accessed from the end by using negative offsets from the end.

    $stooges[-1] # Iggy

Reading a non-existent element gives undef.

    $stooges[47] # undef

The length of an array is its scalar value

Put an array in scalar context to get its length. Some people like to explicitly use scalar. Some don't.

    my $stooge_count = scalar @stooges; # 4

    my $stooge_count = @stooges;        # 4

Don't take the length of an array with length. That gives the length of a string.

    my $moe_length = length $stooges[@stooges/2];
                     length $stooges[2];
                     length 'Moe';
                     3;

Arrays have no boundaries

Arrays don't have any finite size, and don't have to be predeclared. Arrays change in size as necessary.

Arrays are also not sparse. This code makes a 10,000-element array.

    my @array = ();
    $array[10000] = 'x';

@array is now 10,001 elements long (0-10,000), of which only one is populated. The other 10,000 are undef.

Arrays flatten out and do not nest

Unlike PHP, arrays flatten into one big list when combined:

    my @sandwich = ( 'PB', 'J' );
    my @other_sandwich = ( 'B', 'L', 'T' );
    my @ingredients = ( @other_sandwich, @sandwich );
    # ( 'B', 'L', 'T', 'PB', 'J' )

This means you can't have an array "contain" another array, or a hash. To do that, you need references http://perl101.org/references.html.

Lists can have extra commas

One of the greatest features of Perl is the ability to have an extra comma at the end of a list. For example:

    my @array = (
        'This thing',
        'That thing',
    );

This makes adding or deleting items super easy when you edit your code, since you don't have to treat the last as a special case:

    my @array = (
        'This thing',
        'That thing',
        'The other thing',
    );

Use arrays like queues and stacks

shift removes from the beginning of the array:

    my $next_customer = shift @customers;

unshift adds to the beginning of an array:

    unshift @customers, $line_jumper;

push adds to the end of an array:

    push @customers, $dio; # The last in line

pop removes from the end of an array:

    my $went_home = pop @customers;

Extract sections of an array with array slices

Array slices are just array accesses with multiple indices.

    my @a = 'a'..'z'; # 26 letters

    # a, e, i, o, u...
    my @vowels = @a[0,4,8,14,20];

    # And sometimes "y"
    push( @vowels, $a[-2] ) if rand > .5;

Note that when accessing an array slice, the sigil is @, not $, because you're returning an array, not a scalar. A common mistake for beginners is to access an array element with a @ sigil, not $, and get back a slice, which is a list:

    # WRONG: Returns a 1-element list, or 1 in scalar context
    my $z = @a[-1];

    # RIGHT: Returns a single scalar element
    my $z = $a[-1];

Assign chunks of an array with array slices

You can have array slices as lvalues, or values on the left side of the equals sign that can be assigned to.

    # Replace vowels with uppercase versions
    @a[0,4,8,14,20] = qw( A E I O U );

    # Swap first and last elements
    @a[0,-1] = @a[-1,0];

Note that the left and right slices must be of the same size. Any missing values on the right side of the equals sign will be replaced with undef.

Modify arrays in-place with splice

splice lets you splice arrays into other arrays. Let's look at a few common ways of doing it wrong that should illustrate its usefulness:

    my @a = qw(Steve Stu Stan);
    $a[1] = ['Stewart', 'Zane'];
    # @a = ('Steve', ARRAY(0x841214c), 'Stan')
    # Memory address to an array reference

    my @a = qw(Steve Stu Stan);
    my @b = qw(Stewart Zane);
    $a[1] = @b;
    # @a = ('Steve', 2, 'Stan')
    # Returns a scalar reference, the length of @b

Now let's use splice:

    @a = qw(Steve Stu Stan);
    splice @a, 1, 1, 'Stewart', 'Zane';
    # @a = ('Steve', 'Stewart', 'Zane', 'Stan')
    # This is just what we wanted

Let's break down the argument list for splice: first, we name the array we're operating on (@a); second, we define the offset (how far into the list we want the splice to start); third, we specify the length of the splice (how far forward from the offset we'll be deleting to make room for the new list); finally, we list the items we want inserted.

If all else fails, perldoc -f splice.

Process arrays easily with map

map is essentially a foreach loop that returns a list.

You can use it to convert an array into a hash:

    my @array = ( 1, 2, 3, 4, 5 );
    my %hash = map { $_ => $_ * 9 } @array;
    # %hash = ( 1 => 9, 2 => 18, 3 => 27, 4 => 36, 5 => 45 )

or to transform a list:

    my @array = ( 'ReD', 'bLue', 'GrEEN' );
    my @fixed_array = map(ucfirst, map(lc, @array)); # note the nested 'map' functions
    # @fixed_array = ( 'Red', 'Blue', 'Green' )

Watch out, though: If you modify $_, you will modify the source data. This means the above might be changed to:

    my @array = ( 'ReD', 'bLue', 'GrEEN' );
    map { $_ = ucfirst lc $_ } @array;
    # @array = ( 'Red', 'Blue', 'Green' )

Select items out of an array with grep

grep is essentially a foreach loop that returns a list, but unlike map, it will only return elements that cause the condition to return true.

    my @array = ( 0, 1, 2, 3, 4, 5 );
    my @new_array = grep { $_ * 9 } @array;
    # @new_array = ( 1, 2, 3, 4, 5 );

It will modify the source data the same way as map, however:

    my @array = ( 0, 1, 2, 3, 4, 5 );
    my @new_array = grep { $_ *= 9 } @array;
    # @array = ( 0, 9, 18, 27, 36, 45 );
    # @new_array = ( 9, 18, 27, 36, 45 );

We can also pass regular expressions into grep; in this example, we want only people with the surname 'Doe' put into our new array:

    my @people = (
        'John Doe',
        'Jane Doe',
        'Joe Sixpack',
        'John Q. Public',
    );

    my @does = grep { $_ =~ /\bDoe$/ } @people;
    # @does = ('John Doe', 'Jane Doe');

or even shorter

    my @does = grep { /\bDoe$/ } @people;

Want to contribute?

Submit a PR to github.com/petdance/perl101


Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.