Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

perl sorting array: leave an item starts with # in-place

Tags:

sorting

perl

Is there a way to modify sort that any string starts with # is ignored i.e. keep its index?

For example:

my @stooges = qw(
        Larry
        Curly
        Moe
        Iggy
    );

my @sorted_stooges = sort @stooges;

@sorted_stooges should give:

Curly
Iggy
Larry
Moe

Now, if i add # to Curly

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

my @sorted_stooges = sort @stooges;

i would like @sorted_stooges to be:

Iggy
#Curly
Larry
Moe
like image 801
ealeon Avatar asked Dec 06 '22 12:12

ealeon


2 Answers

In-place solutions:

my @indexes_to_sort = grep { $array[$_] !~ /^#/ } 0..$#array;
my @sorted_indexes = sort { $array[$a] cmp $array[$b] } @indexes_to_sort;
@array[@indexes_to_sort] = @array[@sorted_indexes];

or

my @indexes_to_sort = grep { $array[$_] !~ /^#/ } 0..$#array;
@array[@indexes_to_sort] = sort @array[@indexes_to_sort];

or

my $slice = sub { \@_ }->( grep { !/^#/ } @array );
@$slice[0..$#$slice] = sort @$slice;

(Unfortunately, @$slice = sort @$slice; doesn't work —It replaces the elements of @$slice rather than assigning to them— but a suitable alternative was found.)

like image 185
ikegami Avatar answered Jan 09 '23 20:01

ikegami


Extract the elements to be sorted, then update the original array with the sorted elements:

my @stooges = qw( Larry #Curly Moe Iggy );
my @sorted_items = sort grep { not /^#/ } @stooges;
my @sorted_stooges = map { /^#/ ? $_ : shift @sorted_items } @stooges;
say for @sorted_stooges;

In their answer, @ikegami suggests a variant of this approach where the indexes of the elements to be sorted are extracted, rather than the elements themselves. That solution allows the array elements to be exchanged elegantly with a list slice.

like image 40
amon Avatar answered Jan 09 '23 20:01

amon