3
votes

Comment diviser les valeurs de tableau en de nouveaux tableaux séparés en Perl?

Je suis un débutant dans l'apprentissage de perl. Ce que j'essaie de faire ici, c'est de diviser le tableau @value et de l'insérer dans un nouveau tableau. mon problème est que je ne sais pas exactement comment faire fonctionner mon codage en boucle et obtenir le résultat souhaité.

Est-il possible d'obtenir le résultat souhaité en utilisant cette méthode ou existe-t-il une autre alternative / moyen résultat?

Mon code est comme ci-dessous;

my @separated = ();
my @separated1 = ();
my @separated2 = ();
my @separated3 = ();
my $counter = 0;
my @values = "aaa 111 AAA bbb 222 BBB ccc 333 CCC ddd 444 DDD";

foreach (@values) {
my @separated = split(' ', $_);
push @separated1, $separated[0];
push @separated2, $separated[1];
push @separated3, $separated[2];
}
$counter++

print "separated1 = @separated1\n";
print "separated2 = @separated2\n";
print "separated3 = @separated3\n";

Résultat que j'ai obtenu;

séparé1 = aaa

séparé2 = 111

Separated3 = AAA

Résultat souhaité;

séparé1 = aaa bbb ccc ddd

séparé2 = 111222333 444

Separated3 = AAA BB CCC DD


2 commentaires

en fait, vous n'utilisez pas votre variable $ counter. vous l'incrémentez, mais n'y accédez jamais. je suppose que vous vouliez l'utiliser comme index pour vos tableaux.


Cette ligne: my @values ​​= "aaa 111 AAA bbb 222 BBB ccc 333 CCC ddd 444 DDD" ... attribue une valeur scalaire à un tableau. Il met effectivement cette valeur scalaire dans le premier emplacement du tableau @value . Vous pouvez faire un split ici directement: my @values ​​= split / /, "aaa 111 AAA bbb 222 BBB ccc 333 CCC ddd 444 DDD"; Une fois cela en place , le reste est de prendre 3 valeurs à la fois etc etc.


6 Réponses :


5
votes
my @moos;
my @values = split(' ', $input);
while (@values) {
   my %moo; @moo{qw( foo bar qux )} = splice(@values, 0, 3);
   push @moos, \%moo;
}

2 commentaires

La première solution mettra des valeurs non définies dans les résultats si le nombre d'éléments dans les $ values ​​ d'origine n'est pas divisible par 3.


@Silvar, c'est intentionnel, il serait donc préférable de souligner que la solution AoA ne fait pas cela.



5
votes

Une occasion rare où la boucle for de style C est appropriée, pour itérer sur tous les 3 éléments

my @sep = map { [ @values[@$_] ] } part { $_%3 } 0..$#values;

Cela suppose que le tableau a effectivement tous les triplets, ou mieux vérifier chaque élément.

/ p>

Mais il est normalement beaucoup plus agréable de travailler avec une seule structure qu'avec un ensemble de tableaux parallèles. Par exemple, utilisez un tableau avec des éléments qui sont des références de tableau

[
  ["aaa", "bbb", "ccc", "ddd"],
  [111, 222, 333, 444],
  ["AAA", "BBB", "CCC", "DDD"],
]

où la double itération peut être évitée avec un plus propre

for my $i (0..$#values) { 
    push @{$sep[$i%3]}, $values[$i] 
}

qui remplace les deux boucles.

Ceci imprime

use Data::Dump qw(dd);

my @sep;

for (my $i=0; $i <= $#values; $i += 3) { 
    for my $j (0..2) { 
        push @{$sep[$j]}, $values[$i+$j]; 
    }
}

dd \@sep;

J'utilise Data :: Dump pour voir des données complexes. Une alternative dans le noyau est Data :: Dumper .


Et puis il y a de nombreux modules avec toutes sortes de routines utilitaires pour travailler avec des listes.

Par exemple, en utilisant part de List :: MoreUtils pour partitionner le tableau @values ​​ p>

my $string = 'aaa 111 AAA bbb 222 BBB ccc 333 CCC ddd 444 DDD';

my (@sep1, @sep2, @sep3);

my @values = split ' ', $string;

for (my $i=0; $i <= $#values; $i += 3) {
    push @sep1, $values[$i];
    push @sep2, $values[$i+1];
    push @sep3, $values[$i+2];
}

Ceci produit le même @sep avec arrayrefs que ci-dessus.

La partie renvoie une liste de arrayrefs, contenant chacun des indices car il partitionnait la liste des indices de @values ​​. Ensuite, dans map , chaque arrayref est évalué dans sa liste d'indices ( @ $ _ ), qui est utilisé pour prendre la tranche correspondante de @values ​​; cette liste est utilisée pour créer un arrayref avec [] . Ainsi, map renvoie une liste de arrayrefs, avec des valeurs partitionnées selon les besoins.

Pour travailler avec des références, veuillez consulter le tutoriel perlreftut et référence perlref


0 commentaires

3
votes

Une autre version utilisant part de la liste non-core mais très utile :: Module MoreUtils , qui partitionne directement les éléments:

sep1: aaa bbb ccc ddd
sep2: 111 222 333 444
sep3: AAA BBB CCC DDD

imprime

#!/usr/bin/perl
use warnings;
use strict;
use feature qw/say state/;
use List::MoreUtils qw/part/;

my $str = "aaa 111 AAA bbb 222 BBB ccc 333 CCC ddd 444 DDD";

my ($sep1, $sep2, $sep3) = part { state $i = 0; $i++ % 3 } split(' ', $str);

say "sep1: @$sep1";
say "sep2: @$sep2";
say "sep3: @$sep3";

La magie ici est avec state , qui finit par créer une variable locale au bloc dans lequel il se trouve et qui conserve sa valeur plusieurs évaluations du bloc.


0 commentaires

3
votes

Un autre travail pour List :: UtilsBy :

use strict;
use warnings;
use List::UtilsBy 'bundle_by', 'unzip_by';

my $string = 'aaa 111 AAA bbb 222 BBB ccc 333 CCC ddd 444 DDD';
my @vals = split ' ', $string;
my ($sep1, $sep2, $sep3) = unzip_by { @$_ } bundle_by { [@_] } 3, @vals;

print "sep1: @$sep1\nsep2: @$sep2\nsep3: @$sep3\n";


0 commentaires

2
votes

Cette expression peut vous aider à obtenir les résultats souhaités:

const repeat = 1000000;
const start = Date.now();

for (var i = repeat; i >= 0; i--) {
	const string = 'aaa 111 AAA bbb 222 BBB ccc 333 CCC ddd 444 DDD';
	const regex = /([a-z]+\s)([0-9]+\s)([A-Z]+)/gm;
	var match = string.replace(regex, "$1");
}

const end = Date.now() - start;
console.log("YAAAY! \"" + match + "\" is a match 💚💚💚 ");
console.log(end / 1000 + " is the runtime of " + repeat + " times benchmark test. 😳 ");


0 commentaires

2
votes

J'aime les solutions de @ikegami et @zdim. @ zdim utilise part () de List :: MoreUtils m'a rappelé natatime:

my @values = split(' ', "aaa 111 AAA bbb 222 BBB ccc 333 CCC ddd 444 DDD"); 
use List::MoreUtils 'natatime';              
my $nata_iter = natatime 3, @values ;
my @aoa ;           
while (my @tmp = $nata_iter->()) { push @aoa, \@tmp; };

Pas vraiment une considération mais peut-être d'intérêt: en utilisant un tableau temporaire ( @tmp ) pour stocker la sortie de l'itérateur, les @values ​​ d'origine restent intactes alors que splice () plus simple est destructif.


0 commentaires