Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I have an array that holds array refs, I also have a list of items to skip to the end of the selection, so I thought I would remove them and push them back to the end of the array so I created another array to hold the new list.
if this how it should be done?
while (@array1) { next if defined $skip{$_->[0]}; push @array2, shift @array1; }

Replies are listed 'Best First'.
Re: changing array elements
by grinder (Bishop) on Nov 29, 2002 at 08:50 UTC

    You want to move certain array elements to the end? I'd do it like this:

    my @front, @back; while( @array1 ) { if( exists $skip{$_->[0]} ) { push @back, $_; else { push @front, $_; } } my @array2 = (@front, @back);

    The while loop could also be written as

    push @{exists $skip{$_->[0]} ? \@back : \@front}, $_;

    ... and from there you could always carry on as far as

    push @{exists $skip{$_->[0]} ? \@back : \@front}, $_ for @array;

    ... and do away with the while but that requires a much more advanced understanding of Perl and I'm not sure that it's any clearer. And of course it becomes a real pain to step through it in the debugger... And of course I may have completely misunderstood what you're trying to do :)


    print@_{sort keys %_},$/if%_=split//,'= & *a?b:e\f/h^h!j+n,o@o;r$s-t%t#u'
Re: changing array elements
by jmcnamara (Monsignor) on Nov 29, 2002 at 09:01 UTC

    Here is one way of doing it using grep.
    #!/usr/bin/perl -w use strict; my @array = ([1], [2], [3], [4], [5]); my %skip = (3 => 1); my @keep = grep {not exists $skip{$_->[0]}} @array; my @skip = grep { exists $skip{$_->[0]}} @array; my @new = (@keep, @skip);

    If the array of data is very large it may be inefficient to use two calls to grep. In which case a while loop solution as shown by grinder would be better.

    --
    John.

Re: changing array elements
by jmcnamara (Monsignor) on Nov 29, 2002 at 10:16 UTC

    I initially thought about a solution that used sort but the comparison behaviour for equal items is different between perl versions:
    #!/usr/bin/perl -wl use strict; my @array = (2, 3, 4, 5, 1, 7, 11, 8, 9, 6, 10, "End" ); my %skip = (3 => 1, 6 => 1); my @new = sort {exists $skip{$a} <=> exists $skip{$b}} @array; print "@new"; __END__ $ perl5.8.0 sort_end2.pl 2 4 5 1 7 11 8 9 10 End 3 6 $ perl5.6.0 sort_end2.pl 2 End 4 5 1 7 11 8 9 10 3 6

    Update: Changed the test data to make it clearer what the desired output was.

    The difference is due to the the fact that 5.8 uses merge sort and 5.6 uses quick sort. From perlfunc in 5.8:

    Perl 5.6 and earlier used a quicksort algorithm to implement sort. That algorithm was not stable,and could go quadratic. (A stable sort preserves the input order of elements that compare equal.

    --
    John.