我想按十六进制数字和字母对数组进行排序,但我不知道怎么做。我的数组看起来像这样:
my @array = (
"{John}{1} is a boy", "{Emily}{a} is a girl", ..., "{Alba}{f} is a brand"
);
我想首先按字母顺序在第一个{}
中对名称进行排序,然后按第二个{}
按十六进制数排序,而不管后面的单词。
my @sorted = sort { $a <=> $b } @array;
my @sorted1 = sort { hex $a <=> hex $b } @sorted;
print "@sorted1\n";
我尝试这样的东西,但它不起作用。我如何按照上面描述的方式对数组进行排序?
答案 0 :(得分:4)
sort {
my @a_keys = $a =~ /\{([^{}]*)\}/g;
my @b_keys = $b =~ /\{([^{}]*)\}/g;
$a_keys[0] cmp $b_keys[0]
||
hex($a_keys[1]) <=> hex($b_keys[1])
}
答案 1 :(得分:1)
我希望你的代码不起作用的原因很明显。
my @sorted = sort { $a <=> $b } @array;
my @sorted1 = sort { hex $a <=> hex $b } @sorted;
这里有两个问题。首先,你的第二种方法就是覆盖第一种。你运行的第一种是完全没有意义的。您的代码与以下内容具有完全相同的效果:
my @sorted1 = sort { hex $a <=> hex $b } @array;
其次,你正在按错误的方式排序。你的第一个排序是按整个字符串排序,第二个排序是通过hex()
函数传递的整个字符串排序(假设你的字符串不是有效的十六进制字符串,那不是一个好主意)。
让我们分别解决这两个问题。
按两种不同的方式排序实际意味着什么?通常,它意味着各种等级 - 一种比另一种更重要。这意味着“按此排序,如果两个记录具有相同的值,则按此次要值对其进行排序”。在你的情况下,你可能会说“按第一对大括号之间的字符串排序,如果两个记录在那里有相同的值,那么按第二对大括号之间的十六进制值排序”。当第一个排序值在两个记录中相同时,第二个排序值是“打破平局”。
而Perl的sort
非常适合这样的多层次排序。当你编写一个排序表达式时,它需要返回-1,0或1.如果你比较的两个值不同,它返回-1或1,如果它们是相同的则返回0。并且,由于0是Perl的假值,因此可以轻松地将排序堆叠在一起。
my @sorted = sort {
sort_expression_1
or
sort_expression_2
} @array;
如果sort_expression_1
返回-1或1,那么这是真的,布尔表达式“短路”。如果两个值相同,则sort_expression_1
返回0并且布尔表达式继续评估sort_expression_2
。
那么我们真正想要排序的是什么?好吧,我们需要在大括号之间提取字符串并按那些排序。这样的事情,也许是:
my @sorted = sort {
# Extract the sortable bits into arrays
my @a_bits = $a =~ /\{(.+?)}/g;
my @b_bits = $b =~ /\{(.+?)}/g;
# Compare the strings
$a_bits[0] cmp $b_bits[0]
or
# If the strings are the same, compare the hex numbers
hex($a_bits[1]) <=> hex($b_bits[i])
} @array;
为了更有效地排序,您可以使用“Schwartzian Transform”在开始实际排序之前打破您要排序的位。
my @sorted =
map { $_->[0] }
sort { $a->[1] cmp $b->[1] or hex($a->[2]) <=> hex($b->[2]) }
map { [ $_, /\{(.+?)}/g ] } @array;