Boying
Boying

Reputation: 1434

Perl customized sort

I would like to sort an array and put particular element to the beginning.

Here is my code:

sub MySort {
    my $P = 'node';
    if ($a eq $P) {
        return -1;
    }

    return -1 if $a lt $b;
    return 0  if $a eq $b;
    return 1  if $a gt $b;
}

my @x = qw (abc def xxx yyy ggg mmm node);
print join "\n",sort MySort @x

I expect "node" go to the beginning but it's not working.

Result:

abc
def
ggg
node
mmm
xxx
yyy

Expected Result:

node
abc
def
ggg
mmm
xxx
yyy

Upvotes: 2

Views: 238

Answers (2)

mnille
mnille

Reputation: 1338

You missed the cases when $b is node.

sub MySort {     
    my $P = 'node';
    return  0 if $a eq $P && $b eq $P;
    return -1 if $a eq $P;
    return +1 if $b eq $P;
    return $a cmp $b;
}

my @x = qw (abc def xxx yyy ggg mmm node); 
my @a = sort MySort @x; 

Alternatively:

sub MySort {     
    my $P = 'node';
    return ($a eq $P ? 0 : 1) <=> ($b eq $P ? 0 : 1)
        || $a cmp $b;
}

Upvotes: 5

hobbs
hobbs

Reputation: 239890

If you don't want to write this kind of thing by hand, you can use Sort::ByExample, which is specifically made to sort a list of predefined values to the front of the list, if they appear, and sort the remainder how you like. For your example:

use Sort::ByExample;
my $sorter = Sort::ByExample->sorter(
    ['node'],
    sub { $_[0] cmp $_[1] }
);
my @x = qw (abc def xxx yyy ggg mmm node);
print join "\n", $sorter->(@x);

Or if you really want a sub you can use with the sort builtin:

use Sort::ByExample;
my $mysort = Sort::ByExample->cmp(
    ['node'],
    sub { $_[0] cmp $_[1] }
);
my @x = qw (abc def xxx yyy ggg mmm node);
print join "\n", sort $mysort @x;

Upvotes: 2

Related Questions