2017-03-23 2 views
0

Ich habe ein paar Schlüssel eines Hash, die wie folgt aussehen:Sortierung gemischter Array in Perl

Test21 
Test1 
Test4 
Test2 
Test13 
TestA 
TestB 

ich verschiedene Ansätze versucht, sie entweder die integrierte Sortierfunktion oder zusätzliche Unterprogramme verwenden zu sortieren, aber ich weiß nicht nur scheinen es richtig zu machen.

Meine gewünschte Ausgabe wäre:

Test1 
Test2 
Test4 
Test13 
Test21 
TestA 
TestB 

Einer meiner Ansätze sah wie folgt aus:

#!/usr/bin/perl 

use strict; 
use warnings; 
use Data::Dumper qw(Dumper); 


my % hash = (Test1 => "Hello",Test21 => "Somedata", Test4 => "SomeMoreData",Test2 => "EvenMore",Test13 => "AlotMore",TestA => "Nope", TestB => "EvenMoreNope"); 

foreach my $keys(sort byNumberandAlpha keys %hash){ 
    print "$keys\n"; 
} 


sub byNumberandAlpha{ 

    my @temp_a = split("Test",$hash{$a}); 
    my $element_a = $temp_a[1]; 

    my @temp_b = split("Test",$hash{$b}); 
    my $element_b = $temp_b[1]; 

    if ($element_a =~ /[0-9]/ && $element_b =~ /[0-9]/) { 

     $a <=> $b; 

    }else{ 

     $a cmp $b; 
    } 
} 

OUTPUT:

Use of uninitialized value $element_a in pattern match (m//) at ExpirimentalSorting.pl line 23. 
Test1 
Test13 
Test2 
Test21 
Test4 
TestA 
TestB 

Jede Hilfe zu bekommen diese heraus ist sehr sehr geschätzt.

+0

Oh Entschuldigung, das war ein Tippfehler - aktualisiert. – chrys

Antwort

3

Die Sache mit sort ist, dass Sie nach allem, was Sie mögen, sortieren können, Sie müssen nur sicherstellen, dass Sie die richtigen Werte basierend auf eingefügtem Vergleich zurückgeben.

Also in Ihrem Fall - es scheint, dass Sie auf "das Bit, das nicht Test ist" sortieren und numerisch zuerst und alphabetisch zweitens vergleichen.

Was Sie tun, aber schaut oben Ihre Hash-Schlüssel mit:

my @temp_a = split("Test",$hash{$a}); 

Und das ... nicht wirklich funktionieren, weil in keine Ihrer Beispiele nicht $hash{$a} das Wort enthalten 'Prüfung'.

Also ich glaube, Sie verstehen etwas tiefgründiges.

Ich denke Sie wollen:

sub my_sort { 
    my ($a1) = $a =~ m/Test(\w+)/; 
    my ($b1) = $b =~ m/Test(\w+)/; 

    if ($a1 =~ /\d/ and $b1 =~ /\d/) { 
     return $a1 <=> $b1; 
    } 
    else { 
     return $a1 cmp $b1; 
    } 
} 

Allerdings können Sie es einfacher noch Sort::Naturally

foreach my $keys (nsort keys %hash) { 
    print "$keys\n"; 
} 

(Obwohl das tut Art TestA oben Test1) zu bedienen.

Sie könnten etwas Magie mit dualvar tun, aber das ist ein bisschen wie eine Dose Würmer. obwohl aus Gründen der Neugier:

use Scalar::Util qw (dualvar); 
sub my_sort { 
    $_ = dualvar (s/\D+//r || 999999, $_) for $a, $b; 
    return ($a <=> $b 
     || $a cmp $b); 
} 

Dieser Weg sortiert Sie gefragt (vorausgesetzt, die Zahlen nicht überschreiten 999999) durch die numerische Konvertierung Ihrer ‚nur Text‘ Überlastung Saiten.

So wird Test1 zu einer Dualvar mit (1, "Test1"), die wie erwartet sortiert, aber TestA wird zu duavar (999999, "TestA") - und sortiert hinter allem mit einem 'normalen' Zahlenbereich , aber der Vergleich fällt durch, wenn es zwei gibt, und sie vergleichen auf der Basis der Gleichheit der Zeichenkette.

Wenn Sie das gleiche tun mit 0 (z $_ = dualvar (s/\D+//r || 0, $_) for $a, $b; dann TestA und TestB wieder sortiert nach oben.

+0

Vielen Dank das war genau das, was ich gesucht habe. Ich denke, ich verstehe jetzt meinen Fehler. Ich versuchte mit '$ hash {$ a}' auf die Hash-Werte zuzugreifen und versuchte dabei nach den Werten zu sortieren, die nicht "Test" enthielten. Ist das richtig? – chrys

+1

Sie haben versucht, nach den "Werten" Ihres Hashes zu sortieren, ja. – Sobrique