2011-01-05 3 views
5

Je suis nouveau sur Perl et je suis bloqué par un problème de tri (probablement simple).Tri de groupes en Perl

J'ai hérité du code Perl qui lit les lignes d'un fichier texte en trois tableaux 1D (x, y, z). J'aimerais pouvoir trier ces tableaux en utilisant l'une des dimensions comme clé et en réordonnant les deux autres dimensions.

Par exemple, si mon entrée est:

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

et je sorte par x, je voudrais que le résultat soit:

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

je puisse fusionner les trois tableaux 1-D en une matrice 2-D si cela fait vie Plus facile.

+0

vos données par exemple pourraient être effacées - les valeurs @y et @z sont dans le même ordre que @x. avoir des valeurs très différentes (ou même quelque chose comme 'a', 'b', 'c') rendrait plus clair comment ils doivent être triés – plusplus

Répondre

3
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; 

qui va essentiellement vous donner:

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

cela a bien fonctionné ... merci! – amb

-1

Do

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

Voir aussi sort on perldoc.

+1

Cela ne va pas trier '@ y' ou' @ z'. – mkb

+0

oui, cela va trier l'un des tableaux 1-d. il ne triera pas les deux autres pour correspondre. mon espoir est de pouvoir trier par le tableau x et de faire réordonner les tableaux y et z pour qu'ils correspondent, de sorte que les lignes du fichier texte soient conservées. Je suis désolé si ma question n'était pas claire. --amb – amb

0

La fusion peut en effet rendre la vie plus facile.

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

peut le faire. Vous ne voudrez bien sûr pas écrire tout cela à la main!

0

Si @x a la même taille que @y et @z, il n'est pas nécessaire de trier - Vous pouvez utiliser une tranche de tableau à la place!

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; 

Bien sûr, si vous voulez juste trier par ordre numérique, puis en utilisant @x est superflue:

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

Enfin, si vous voulez trier un nombre arbitraire de tableaux, vous pouvez créer un tableau de tableaux, ou passer une liste de références à un pour, ala

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

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

Je ne pense pas que vous puissiez supposer que les valeurs de '@ x' peuvent être utilisées comme indices. Et s'ils sont négatifs ou non uniques? – mkb

+0

Les nombres négatifs ou les répétitions ne seraient pas vraiment gênants (c'est sa spécification, après tout ..), mais un index en dehors du tableau déclenchera des avertissements. Mais ouais, programmeur caveat. – Hugmeir

+0

Ils sont gênants en ce sens qu'ils vous donneront des résultats incorrects sans avertissement. Essayez de changer le '@ x' non trié à (1,3,3). – mkb

0

avoir un essai avec:

#!/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; 

Sortie:

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

Cela se casse si '@ x' a des valeurs en double. – mkb

10

fusion ensemble tous les tableaux ne sont pas nécessaires.Utilisez sort pour obtenir l'ordre d'index correct pour les éléments en @x:

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

Appliquer ensuite que la commande d'index à tout autre tableau:

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