#!/usr/bin/perl use strict; use warnings; my $op_io = <<'OP_INPUT_AND_OUTPUT'; 'aaa' 1,2 'aaa' 1,2 'aaa' 2,1 'aaa' 2,3 'aaa' 2,3 'aaa' 2,1 'aaa' 3,1 'aaa' 3,1 'aaa' 3,2 'aaa' 3,2 'aaa' 4,1 'aaa' 4,5 'aaa' 4,5 'aaa' 4,1 'bbb' 2,2 'bbb' 2,1 'bbb' 2,5 'bbb' 2,2 'bbb' 2,1 'bbb' 2,5 'bbb' 4,3 'bbb' 4,6 'bbb' 4,6 'bbb' 4,3 'bbb' 4,1 'bbb' 4,2 'bbb' 4,2 'bbb' 4,1 'ccc' 3,3 'ccc' 1,1 'ccc' 3,6 'ccc' 1,3 'ccc' 1,3 'ccc' 2,4 'ccc' 1,1 'ccc' 2,2 'ccc' 6,4 'ccc' 3,3 'ccc' 6,6 'ccc' 3,6 'ccc' 2,2 'ccc' 6,6 'ccc' 2,4 'ccc' 6,4 OP_INPUT_AND_OUTPUT ; my @init; my @want; my $n = 0; foreach my $line ( split /\n/, $op_io ) { ( $init[$n][0], $init[$n][1], $init[$n][2], $want[$n][0], $want[$n][1], $want[$n][2] ) = ( $line =~ m{ \A \'(...)\' \s+ (\d+),(\d+) \s+ \'(...)\' \s+ (\d+),(\d+) }xms ); $n++; } # At this point, @init and @want are both AoA. # unique X values for each group my %x_of; $x_of{$_->[0]}{$_->[1]}++ for @init; # map an X to its relative position in a sorted list of X. foreach my $group ( keys %x_of ) { my @exez = sort { $a <=> $b } keys %{ $x_of{$group} }; @{ $x_of{$group} }{@exez} = 0 .. $#exez; } # Sort first by group, then by X, # then ascending or descending depending on what X's position is. my @out = sort { $a->[0] cmp $b->[0] || $a->[1] <=> $b->[1] || ( ( $x_of{ $a->[0] }{ $a->[1] } % 2 ) ? ( $b->[2] <=> $a->[2] ) : ( $a->[2] <=> $b->[2] ) ) } @init; use Test::More tests => 1; is_deeply( \@out, \@want, 'it works!' );