2010-09-08 9 views
-2

J'ai un tableau de ce genreComment puis-je supprimer les doublons et le tri en même temps en Perl?

@uniqarr = qw(error 0 goodrecordno:6123, error 0 goodrecordno:6143, error 1 goodrecordno:10245, error 1 goodrecordno:10678, error 1 goodrecordno:10698, error 2 goodrecordno:16245, error 2 goodrecordno:16123); 

Je veux que le o/p comme

error 0 goodrecordno:6123 
error 1 goodrecordno:10245 
error 2 goodrecordno:16123 

i.e. chaque Onetime erreur avec son plus bas RECORDNO correspondant. Quelqu'un peut-il m'aider sans utiliser les modules cpan

Merci d'avance.

+3

Hunh? S'il vous plaît gardez à l'esprit lors de l'affichage que Stack Overflow est destiné à être une alternative aux sites d'experts payants. L'utilisation de raccourcis cryptiques pour énoncer votre problème est peu susceptible d'aider quelqu'un à l'avenir. Le tableau s'appellera '@ uniqarr' et à moins que vous ne vouliez une clé appelée' 'goodrecord: 6123, '' (* avec * la virgule dans la clé) vous ne devriez pas mettre de virgules dans une liste 'qw()'. Qu'est-ce que "o/p"? *Sortie*?! Vous pourriez économiser beaucoup de confusion au prix de taper * 4 * caractères supplémentaires. – Axeman

+2

"sans utiliser les modules CPAN"? Pourquoi? – Ether

+0

Désolé patron ...! J'essayais d'apprendre à écrire chaque programme sans les modules cpan. Donc je le veux seulement sans eux bcoz (car) ils pourraient être simples en utilisant des modules cpan.Je veux apprendre la logique de base à partir de la base.Désolé pour l'o/p suivant A partir de maintenant, je vais tout écrire clairement. Merci pour les conseils et suggestions. – Sunny

Répondre

3

Il s'agit du problème minimum-maximum que vous trouverez dans les livres Perl. Vous faites un passage à travers tous les éléments et vous vous rappelez lequel était le plus bas au fur et à mesure. C'est beaucoup mieux que le tri, qui est conçu pour vous de mettre tous les éléments en ordre, ce qui n'est pas ce que vous recherchez.

use strict; 
use warnings; 

# I'll assume those commas were a mistake. You don't need to separate 
# items with commas in a quotewords list 
# If I'm wrong, the process is the same although the data massaging 
# will be a little different 
my @elements = qw(
    error 0 goodrecordno:6123 
    error 0 goodrecordno:6143 
    error 1 goodrecordno:10245 
    error 1 goodrecordno:10678 
    error 1 goodrecordno:10698 
    error 2 goodrecordno:16245 
    error 2 goodrecordno:16123 
    ); 

my %lowest; 
while(my($error, $number, $goodrecno) = splice @elements, 0, 3,()) 
    { 
    my($recno) = $goodrecno =~ /(\d+)/; 

    # This hash remembers the lowest $recno. If you find another 
    # a lower number, you replace the previous value. 
    $lowest{$number} = $recno if( 
     ! exists $lowest{$number} 
      || 
     $recno < $lowest{$number} 
     ); 
    } 

Une fois que vous avez créé le hachage qui a les éléments les plus bas, vous imprimez simplement:

foreach my $number (sort { $a <=> $b } keys %lowest) { 
    print "error $number goodrecordno:$lowest{$number}\n"; 
    }; 

Cela vous donne la sortie que vous recherchez:

error 0 goodrecordno:6123 
error 1 goodrecordno:10245 
error 2 goodrecordno:16123 

C'est un modèle de base pour ce genre de problèmes. Étape 1: scannez les données pour vous souvenir de ce que vous voulez, en utilisant un hash pour saisir ces données. Étape 2: sortie du contenu du hachage.

1

Pour supprimer les doublons, la meilleure façon est d'utiliser l » uniqList::MoreUtils,:

use List::MoreUtils 'uniq'; 
my @unique_list = uniq @list; 

ou sans CPAN (bien que cela soit rarement nécessaire):

my %values; 
@values{@list} =(); 
my @unique_list = keys %values; 

Vous pouvez trier la liste en utilisant le tri des fonctions intégrées - voir perldoc -f sort et perldoc -q 'How do I sort an array'. Par ailleurs, les données que vous avez citées ne correspondent pas au comportement que vous décrivez. Si vous déclarez un tableau comme

@uniqarr = qw(error 0 goodrecordno:6123, error 0 goodrecordno:6143, error 1 goodrecordno:10245, error 1 goodrecordno:10678, error 1 goodrecordno:10698, error 2 goodrecordno:16245, error 2 goodrecordno:16123); 

... alors son contenu contiendra:

(
    'error', 
    '0', 
    'goodrecordno:6123,', 
    'error', 
    '0', 
    'goodrecordno:6143,', 
    'error', 
    '1', 
    'goodrecordno:10245,', 
    'error', 
    '1', 
    'goodrecordno:10678,', 
    'error', 
    '1', 
    'goodrecordno:10698,', 
    'error', 
    '2', 
    'goodrecordno:16245,', 
    'error', 
    '2', 
    'goodrecordno:16123' 
); 

Ce que vous devez faire est de lire les données dans une table de hachage , puis Parse selon vos critères Je ne peux pas aller plus loin car ce n'est pas du tout clair ce que vous cherchez. Veuillez lire les informations perldoc perldata et perldoc perldsc pour en savoir plus sur les structures de données Perl.

+0

Vous vous souciez seulement des clés, '@values ​​{@list} =();' est plus rapide et utilise moins de mémoire. –

+0

@Chas: agréable; Je n'ai pas réalisé que les tranches de hachage fonctionneraient sans une liste RHS de la même longueur. – Ether

+0

Vous ne voulez pas trier. C'est trop de travail pour ce problème. Je ne vois pas comment cette réponse répond réellement au problème. Les éléments uniques ne sont pas utiles ici. –

0

Comme tout le monde a déjà souligné votre premier problème est que qw() est inapproprié pour établir cette matrice.

Il y a plusieurs façons de le faire correctement, je vais utiliser un tableau de hachage ici qui est l'option la plus verbeuse, il est assez facile de modifier la technique à la structure que vous choisissez.


@uniqarr = (
    { error => 0, goodrecordno => 6123, }, 
    { error => 0, goodrecordno => 6143, }, 
    { error => 1, goodrecordno => 10245, }, 
    { error => 1, goodrecordno => 10678, }, 
    { error => 1, goodrecordno => 10698, }, 
    { error => 2, goodrecordno => 16245, }, 
    { error => 2, goodrecordno => 16123, }, 
); 

Ensuite, pour extraire chaque instance d'erreur avec le plus bas goodrecordno, nous pouvons faire ce qui suit.

Nous importons d'abord min de List :: Util. Ce module est le noyau Perl et ne nécessite pas de CPAN.

Ensuite, restructurez l'entrée @uniqarr. C'est beaucoup plus facile pour ce que nous voulons grouper par les valeurs d'erreur. Donc, by_error est un hachage de tableaux. La clé du hachage est la valeur d'erreur, le tableau contient toutes les valeurs goodrecordno.

Enfin, nous produisons la sortie désirée. Le bouclage à travers le hachage signifie que nous itérons sur chaque valeur d'erreur, triés pour fournir l'ordre de sortie correct. Ensuite, nous extrayons la valeur minimum goodrecordno. Ce qui laisse juste l'impression de la sortie.


use List::Util qw(min); # In core Perl, not CPAN 

# Restructure input 
my %by_error; # Hash with error as key, array of goodrecordno as value. 
foreach (@uniqarr) { 
    push @{$by_error{$_->{error}}}, $_->{goodrecordno}; 
} 

# Output as desired 
foreach my $error (sort keys %by_error) { 
    my $min_no = min @{$by_error{$error}}; 
    print "error $error goodrecordno:$min_no\n"; 
} 
Questions connexes