amb
amb

Reputation: 335

Array sorting in Perl

I am new to Perl and stuck with a (likely simple) array sorting problem.

I've inherited some Perl code that reads lines from a text file into three 1-D arrays (x,y,z). I'd like to be able sort these arrays using one of the dimensions as the key and reordering the other two dimensions to match.

For example, if my input is:

and I sort by x, I'd like the result to be:

I could merge the three 1-D arrays into a 2-D array if that makes life easier.

Upvotes: 5

Views: 2979

Answers (6)

Benoit
Benoit

Reputation: 79155

Do

@a = sort { $a <=> $b } @a;

Also see sort on perldoc.

Upvotes: -1

mob
mob

Reputation: 118595

Merging all the arrays together isn't necessary. Use sort to get the correct index ordering for the elements in @x:

@sort_by_x = sort { $x[$a] <=> $x[$b] } 0 .. $#x;    #   ==> (0, 2, 1)

Then apply that index ordering to any other array:

@x = @x[@sort_by_x];
@y = @y[@sort_by_x];
@z = @z[@sort_by_x];

Upvotes: 10

Toto
Toto

Reputation: 91373

Have a try with:

#!/usr/bin/perl 
use 5.10.1;
use strict;
use warnings;
use Data::Dumper;

my @x = (1, 3, 2);
my @y = (11,13,12);
my @z = (21,23,22);

my (%y, %z);

@y{@x} = @y;
@z{@x} = @z;

my @xs = sort @x;
my @ys = @y{@xs};
my @zs = @z{@xs};
say Dumper \@xs,\@ys,\@zs;

Output:

$VAR1 = [
          1,
          2,
          3
        ];
$VAR2 = [
          11,
          12,
          13
        ];
$VAR3 = [
          21,
          22,
          23
        ];

Upvotes: 0

zakovyrya
zakovyrya

Reputation: 9689

use strict;
use warnings;
use Data::Dumper;

use List::Util qw(reduce);

my @x = (1, 3, 2);
my @y = (11, 13, 12);
my @z = (21, 23, 22);

my @combined = map { [ $x[$_], $y[$_], $z[$_] ] } 0 .. $#x;
my @sorted = sort { $a->[0] <=> $b->[0] } @combined;
my $split_ref = reduce { push @{$a->[$_]}, $b->[$_] for 0 .. $#$a; $a;} [[], [], []], @sorted;

print Dumper \@combined;
print Dumper \@sorted;
print Dumper $split_ref;

Which will essentially give you:

    [
      [
        1,
        2,
        3
      ],
      [
        11,
        12,
        13
      ],
      [
        21,
        22,
        23
      ]
    ];

Upvotes: 3

Hugmeir
Hugmeir

Reputation: 1259

If @x is the same size as @y and @z, there is no need to sort - You can use an array slice instead!

use strict;
use warnings;
use 5.010;

my @x = (1, 3, 2);
my @y = (11,13,12);
my @z = (21,23,22);

say join ', ', @y;
@y = @y[ map { $_ - 1 } @x ]; #We use map create a lists of the values of elements in @x, minus 1.
say join ', ', @y;

Of course, if you just want to sort by numerical order, then using @x is superfluous:

@y = sort { $a <=> $b } @y;

Finally, if you want to sort an arbitrary number of arrays, you could create an array of arrays, or pass a list of references to a for, ala

my @indexes = map { $_ - 1 } @x;

for my $array_ref ( \@x, \@y, \@z ) {
    @$array_ref = @{$array_ref}[@indexes];
}

Upvotes: 0

Matt K
Matt K

Reputation: 13832

Merging indeed may make life easier.

@sorted = sort { $a->[0] <=> $b->[0] } 
    ( [$x[0], $y[0], $z[0]], [$x[1], $y[1], $z[1]], [$x[2], $y[2], $z[2]] );

might do it. You'll of course not want to write all that out by hand!

Upvotes: 0

Related Questions