Search code examples
perlgrepquicksortsplice

Perl 5 - How does this script work and what is @_ and $_?


I'm trying to figure out what's going on in this Perl Script. The Comments are me thinking, thank you, if you devote your time helping me. I have very little experience with Perl but have some knowledge in shell scripting.

I think @_ is a list of parameters passed down in a subroutine and $_ a global variable, I struggle to make sense of their actual purpose in this script.

#!/bin/perl
sub quick_sort {
    # exit condition, when subset contains less than 2 elements
    return @_ if @_ < 2; 

    # choosing pivot element, using subset as input, rand as random offset, no idea what the 1 is for, man says "int fd_out"
    my $p = splice @_, int rand @_, 1;

    # actual recursion and the main source of my confusion
    # calling quicksort(smaller pivot, pivot, quicksort(greater pivot))
    quick_sort(grep $_ < $p, @_), $p, quick_sort(grep $_ >= $p, @_);
}

# running the damn thing, no greater secrets here, i guess 
my @a = (4, 65, 2, -31, 0, 99, 83, 782, 1);
@a = quick_sort @a;

print "@a\n";

Solution

  • quick_sort(grep $_ < $p, @_), $p, quick_sort(grep $_ >= $p, @_);
    

    Let's break this down:

    @_ is the array of function arguments.

    $_ is a temporary scalar variable used as a placeholder in some contexts.

    grep $_ < $p, @_
    

    This is an expression which uses the grep builtin function to create a list consisting of all the elements from @_ which satisfy the condition $_ < $p -- that is, all the elements which are numerically less than the pivot.

    The resulting list is passed to quick_sort, so the result is a sorted list of all the elements less than the pivot.

    The same thing happens on the other side:

    quick_sort(grep $_ >= $p, @_);
    

    This takes all the elements of @_ which are greater than the pivot and sorts those.

    Finally:

    quick_sort(grep $_ < $p, @_), $p, quick_sort(grep $_ >= $p, @_);
    

    The comma expression creates a list consisting of:

    1. A sorted list of all the arguments less than the pivot element.

    2. The pivot element.

    3. A sorted list of all the arguments greater than the pivot element.

    And when you put those all together, you end up with a sorted list of all the arguments to the function.

    But this is all silly. Perl has a builtin sort function; you could express the same thing much more concisely as @a = sort { $a <=> $b } @a, and it'd actually be much faster.