2009-08-19 7 views
5

Est-ce que quelqu'un sait comment mélanger deux tableaux aléatoirement exactement de la même manière en Perl? Par exemple, supposons que j'ai ces deux tableaux:Comment mélanger deux tableaux exactement de la même manière en Perl?

avant de mélanger: tableau 1: 1, 2, 3, 4, 5 tableau 2: a, b, c, d, e

Après brassage : tableau 1: 2, 4, 5, 3, 1 tableau 2: b, d, e, c, a

Chaque élément de chaque tableau est donc lié à son élément équivalent.

Répondre

22

Essayez (quelque chose comme) ceci:

use List::Util qw(shuffle); 
my @list1 = qw(a b c d e); 
my @list2 = qw(f g h i j); 
my @order = shuffle 0..$#list1; 
print @list1[@order]; 
print @list2[@order]; 
+1

++ pour l'utilisation de tranches de liste. Je ne me souviens pas de les utiliser aussi souvent que je le devrais. – daotoad

+1

@daotoad: J'adore doublement les tranches de hachage: @foobar {qw (foo bar baz qux)} :-) –

+0

Merci beaucoup! – Abdel

6

Utilisez List::Utilshuffle pour mélanger une liste d'index et mapper les résultats sur les tableaux.

use strict; 
use warnings; 

use List::Util qw(shuffle); 

my @array1 = qw(a b c d e); 
my @array2 = 1..5; 

my @indexes = shuffle 0..$#array1; 
my @shuffle1 = map $array1[$_], @indexes; 
my @shuffle2 = map $array2[$_], @indexes; 

Mise à jour Utilisez Chris solution de Jester-Young. Array slices sont un meilleur choix que j'aurais dû penser.

+1

Vous n'avez pas besoin d'utiliser 'map'; Les tableaux peuvent être indexés par un autre tableau, qui contient les indices à obtenir. :-) –

9

Première: tableaux parallèles sont un signe potentiel de mauvais code; vous devriez voir si vous pouvez utiliser un tableau d'objets ou de hachages et vous épargner ce problème.

Néanmoins:

use List::Util qw(shuffle); 

sub shuffle_together { 
    my (@arrays) = @_; 

    my $length = @{ $arrays[0] }; 

    for my $array (@arrays) { 
    die "Arrays weren't all the same length" if @$array != $length; 
    } 

    my @shuffle_order = shuffle (0 .. $length - 1); 

    return map { 
    [ @{$_}[@shuffle_order] ] 
    } @arrays; 
} 

my ($numbers, $letters) = shuffle_together [1,2,3,4,5], ['a','b','c','d','e']; 

Fondamentalement, utilisez shuffle pour produire une liste d'indices dans un ordre aléatoire, puis couper tous les tableaux avec la même liste d'indices.

+4

+1 pour souligner que vous ne devriez pas avoir de tableaux parallèles, mais des tableaux de quelque chose d'autre (tableaux, hachages, objets,) qui gardent les données ensemble physiquement. – Tanktalus

+1

+1 pour s'assurer que la matrice A la même taille – lexu

+2

@Tanktalus: "ne devrait pas" est trop fort. C'est l'odeur du code, mais parfois c'est comme ça. – ysth

6

Voici une autre façon:

use strict; 
use warnings; 

use List::AllUtils qw(pairwise shuffle); 

my @list1 = qw(a b c d e); 
my @list2 = qw(f g h i j); 

my @shuffled_pairs = shuffle pairwise{[$a, $b]} @list1, @list2; 

for my $pair (@shuffled_pairs) { 
    print "$pair->[0]\t$pair->[1]\n"; 
} 

Sortie:

 
C:\Temp> sfl 
e  j 
b  g 
d  i 
a  f 
c  h 

De cette façon, vous pouvez itérer directement sur @shuffled_pairs sans avoir besoin de garder un tableau supplémentaire pour les indices et éviter les boucles de style C .

+0

+1 pour utiliser la façon dont je pensais. – Axeman

Questions connexes