2011-01-05 12 views
5

Jestem nowym użytkownikiem Perla i utknąłem z (prawdopodobnie prostym) problemem sortowania tablic.Sortowanie tablic w Perlu

Odziedziczyłem kod Perla, który czyta linie z pliku tekstowego na trzy tablice 1-D (x, y, z). Chciałbym móc sortować te tablice używając jednego z wymiarów jako klucza i dopasowując pozostałe dwa wymiary do siebie.

Na przykład, jeśli wejściowy:

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

i sortowania według x, że i jak wynik to:

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

mogę połączyć trzy układy 1-D w tablicy 2-D, jeśli to ma żywotność łatwiej.

+0

Twój przykład dane mogą zostać usunięte - wartości w @y i @z są w tej samej kolejności co @x. o bardzo różnych wartościach (lub nawet takich jak "a", "b", "c") sprawiłoby, że byłby on dokładniejszy, dokładnie w jaki sposób mają być sortowane. – plusplus

Odpowiedz

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; 

które zasadniczo dają ci:

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

to działało świetnie ... dzięki! – amb

-1

Czy

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

także zobaczyć sort on perldoc.

+1

To nie posortuje "@ y" lub "@ z". – mkb

+0

tak, to będzie sortować jedną z tablic 1-d. nie sortuje pozostałych dwóch pasujących elementów. mam nadzieję, że będę mógł sortować według tablicy x i mieć uporządkowaną tablicę y i z, aby zachować wiersze z pliku tekstowego. Przepraszam, jeśli moje pytanie nie było jasne. --amb – amb

0

Scalenie rzeczywiście może ułatwić życie.

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

może to zrobić. Oczywiście nie będziesz chciał pisać tego wszystkiego ręcznie!

0

Jeśli @x ma taki sam rozmiar jak @y i @z, nie ma potrzeby sortowania - zamiast tego możesz użyć wycinka tablicy!

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; 

Oczywiście, jeśli po prostu chcesz, aby posortować według kolejności numerycznej, a następnie za pomocą @x jest zbędny:

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

Wreszcie, jeśli chcesz uporządkować dowolną liczbę tablic, można utworzyć tablica tablic, lub przekazać listę odnośników do for, ala

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

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

Nie sądzę, że można bezpiecznie założyć, że wartości w '@ x' mogą być używane jako wskaźniki. Co jeśli są negatywne, czy nie wyjątkowe? – mkb

+0

Negatywne liczby lub powtórzenia nie byłyby naprawdę kłopotliwe (to przecież jego specyfikacja ...), ale indeks poza tablicą wywoła ostrzeżenia. Ale tak, zapamiętaj programistę. – Hugmeir

+0

Są kłopotliwe, ponieważ dają niepoprawne wyniki bez ostrzeżenia. Spróbuj zmienić nieposortowane '@ x' na (1,3,3). – mkb

0

spróbować z:

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

wyjściowa:

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

To łamie, jeśli '@ x' ma jakiekolwiek zduplikowane wartości. – mkb

10

łączące wszystkie tablice razem nie jest to konieczne.Użyj sort aby uzyskać prawidłową kolejność indeksu elementów w @x:

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

Następnie stosować tę kolejność indeksu do innego tablicy:

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