Hash et somme
debousole
Messages postés
4
Statut
Membre
-
Pat -
Pat -
Bonjour,
J'ai un tableau ne contenant que des 1 et 0. Il est possible d'avoir 2 fois le même éléments. Je souhaiterai avoir chaque élément qu'une seule fois et faire la somme de chaque colonne et remplacer quand la somme de la colonne est égale à 2 indiquer 1.
tableau initial :
element1 1 0 1
element2 0 1 1
element3 1 1 0
element1 0 0 1
tableau final:
element1 1 0 1
element2 0 1 1
element3 1 1 0
Si quelqu'un peux m'aider s'il vous plaît, je "patauge" depuis un moment merci
J'ai un tableau ne contenant que des 1 et 0. Il est possible d'avoir 2 fois le même éléments. Je souhaiterai avoir chaque élément qu'une seule fois et faire la somme de chaque colonne et remplacer quand la somme de la colonne est égale à 2 indiquer 1.
tableau initial :
element1 1 0 1
element2 0 1 1
element3 1 1 0
element1 0 0 1
tableau final:
element1 1 0 1
element2 0 1 1
element3 1 1 0
Si quelqu'un peux m'aider s'il vous plaît, je "patauge" depuis un moment merci
my $fichier = 'exemple';
open my $fh, '<', $fichier or die "Impossible de lire le fichier $fichier\n";
my %data;
my $i=0;
my $j=0;
while(my $ligne = <$fh>){
$i++;
chomp $ligne;
if($ligne =~ /gene.*/){
$j++;
my ($gene,$champ1,$champ2,$champ3) = split "\t", $ligne;
my $element =$champ1."\t".$champ2."\t".$champ3;
push @{$data{$gene}}, [$element];
}
}
for my $id (keys %data) {
my @array = @{$data{$id}};
$data{$id} = \@array;
}
#print Dumper \%data; #ok bonne vérif
for my $id (keys %data) {
print "--$id\n";
my @tableau=();
my @array = @{$data{$id}};
for my $pair (@array) {
#print ("\t$pair->[0]\n");#ok bonne vérif
#faire la somme de chaque colonne
my @hit = split("\t",$pair->[0]);
for (my $m = 0; $m < @hit ; $m++) {
print "colonne $m - valeur $hit[$m]\n";
}
}
}
close($fh);
Configuration: Linux / Firefox 68.0
3 réponses
-
Salut,
Il ne peut y avoir qu'une répétition d'élément, selon ce que je comprends, et il y a toujours 3 colonnes de données pour chaque élément ?
Si oui, j'aurai fait plus simple avec une regexp et un hash de tableaux :
#!/usr/bin/perl use strict; use warnings; my %data; while (<DATA>) { if (/(element\d+)\s+(\d)\s+(\d)\s+(\d)/) { # la ligne matche et nous avons capturé les 4 données if (!$data{$1}) { # si l'élément n'est pas déjà stocké dans le hash, on crée l'entrée $data{$1} = [$2, $3, $4]; } else { # si l'élément est déjà stocké dans le hash, on retraite les données $data{$1} = [ $2 + $data{$1}[0] == 2 ? 1 : $2 + $data{$1}[0], $3 + $data{$1}[1] == 2 ? 1 : $3 + $data{$1}[1], $4 + $data{$1}[2] == 2 ? 1 : $4 + $data{$1}[2] ]; } } } # affichage ordonné par clef foreach my $elem (sort keys %data) { print "$elem\t$data{$elem}[0]\t$data{$elem}[1]\t$data{$elem}[2]\n"; } __END__ element1 1 0 1 element2 0 1 1 element3 1 1 0 element1 0 0 1
donne sur ton jeu de données :
$ perl 36867025.pl element1 1 0 1 element2 0 1 1 element3 1 1 0
Dal -
Merci bien.
Oui Il ne peut y avoir qu'une répétition d'élément,
J'ai 20 colonnes, en fait il y a toujours un nombre fixe de colonnes de donnée pour chaque élément
Ah oui nettement plus simple...
J'ai avancé et trouvé une solution (sauf pour le remplacement de 2 par 1, un sed après traitement au pire)
open my $fh, '<', $fichier or die "Impossible de lire le fichier $fichier\n";
my %data;
my $i=0;
my $j=0;
while(my $ligne = <$fh>){
$i++;
chomp $ligne;
if($ligne =~ /gene.*/){
$j++;
my ($gene,$champ1,$champ2,$champ3) = split "\t", $ligne;
my $element =$champ1."\t".$champ2."\t".$champ3;
push @{$data{$gene}}, [$element];
}
}
for my $id (keys %data) {
my @array = @{$data{$id}};
$data{$id} = \@array;
}
#print Dumper \%data;
for my $id (keys %data) {
print "--$id\n";
my @tableau=();
my @array = @{$data{$id}};
my @sums;
for my $pair (@array) {
print ("\t$pair->[0]\n");
#faire la somme de chaque colonne quand la somme est égale à 2 remplacer par 1
my @nums = split("\t",$pair->[0]);
my $o = 0;
foreach my $num (@nums){
$sums[$o] += $num;
$o += 1;
}
}
print"=>\t";
foreach my $sum (@sums){
print("$sum\t");
}
print"\n";
}
Encore MERCI-
De rien :-)
1.
Dans ton code, il suffit d'insérer la ligne suivante dans la boucleforeach
entre$sums[$o] += $num;
et$o += 1;
:
$sums[$o] = 1 if $sums[$o] == 2;
Pour rectifier les données mises à 2 en 1.
2.
Ton code semble travailler sur 3 colonnes de données, et non 20.
Tu peux, bien sûr extrapoler ton code (ou le mien) pour traiter 20 colonnes de données, mais cela fait beaucoup de copier-collers de lignes et de variables ou indices à traquer correctement.
Avec une regexp et le modificateurg
tu peux répéter les matches et obtenir le résultat dans un tableau. Que tu aies 3 ou 20 colonnes de données ne changera rien au code.
Si tu n'aimes pas les regexp,split
(que tu utilises), fonctionne en contexte de liste, et te permet d'obtenir directement un tableau des éléments séparés par les tabulations. Tu peux alors supprimer le premier élément du tableau avecshift
pour l'utiliser ultérieurement comme clef de ton hash, et du disposeras du tableau restant sans le premier élément pour en faire ce que tu veux.
C'est à dire :if ($ligne =~ /gene.*/) { # obtention de toutes les colonnes dans un tableau my @arr = split "\t", $ligne; # on retire la donnée en première colonne, qui est notre clef my $key = shift @arr; # le tableau @arr contient désormais les données des colonnes # sauf la première qui a été retirée (...)
-
-
MERCI beaucoup!
Oui mon script est basé sur 3 colonnes pour que je puisse vérifier mon script rapidement...