在perl中对混合数组进行排序

时间:2017-03-23 13:06:18

标签: perl sorting hash key

我有几个哈希的键,如下所示:

Test21
Test1
Test4
Test2
Test13
TestA
TestB

我尝试了几种使用内置排序函数或额外子程序对它们进行排序的方法,但我似乎没有把它弄好。

我想要的输出是:

Test1
Test2
Test4
Test13
Test21
TestA
TestB

我的一种方法看起来像这样:

#!/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;
    }
}

输出:

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

非常感谢任何有关解决这个问题的帮助。

1 个答案:

答案 0 :(得分:3)

sort的东西是你可以按你喜欢的任何东西排序,你只需要确保根据插入的比较返回正确的值。

因此,在您的情况下 - 您似乎正在对未经测试的位进行排序&#39;首先按数字比较,然后按字母顺序进行比较。

您正在做的事情是使用以下方式查找您的哈希键:

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

而且......实际上并没有效果,因为在您的示例的 none 中,$hash{$a}包含了单词&#39; test&#39;。

所以我认为你误解了一些深刻的东西。

我想你想要:

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;
   }
}

但是,您可能会发现使用Sort::Naturally

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

(虽然这确实将TestA排在Test1之上)。

你可以使用dualvar做一些魔术,但那可能是一些蠕虫。为了好奇,但是:

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

这会对您提出的方式(如果数字不超过999999)进行排序,方法是重载“仅”文本的数字转换。字符串。

所以Test1变成了包含(1,&#34; Test1&#34;)的双变量,它按你期望的方式排序,但是TestA变成了双变量(999999,&#34; TestA&#34 ;) - 用“正常”&#39;进行排序。数值范围,但比较&#39;落在&#39;当有两个时,他们根据字符串等价进行比较。

如果您对0执行相同操作(例如$_ = dualvar ( s/\D+//r || 0, $_ ) for $a, $b;,则TestATestB再次排在最前面。