【发布时间】:2011-06-24 17:09:06
【问题描述】:
我有一个哈希值,我想根据大写单词出现在小写单词之前的键进行排序。
例子:
简
简
吉姆
吉姆
【问题讨论】:
-
您的意思是要按特定顺序提取密钥吗?您无法对键的实际存储进行排序,因为散列键是无序的。
-
不,我只想按排序顺序打印出来。实际上并没有在哈希中按排序顺序保存键。
我有一个哈希值,我想根据大写单词出现在小写单词之前的键进行排序。
例子:
简
简
吉姆
吉姆
【问题讨论】:
试试:
@list = ("jane","JIM","JANE","jim");
print sort { uc $a cmp uc $b or $a cmp $b } @list;
【讨论】:
要按顺序获取键,请在散列的键上应用 sort 和自定义排序功能。
my %hash = ( JANE => 1, jane => 2, JIM => 3, jim => 4 );
my @sorted_keys = sort {
lc $a cmp lc $b
|| $a cmp $b
} keys %hash;
custom sort function 首先比较字符串,就好像它们的大小写相同,如果相等,则考虑大小写。
【讨论】:
lc $a cmp lc $b || $b cmp $a
使用自定义排序,首先根据项目的小写表示比较项目(以便“jane”的所有变体出现在“jim”的变体之前),然后通过执行默认的 ASCII 比较来解决平局问题(其中大写在小写之前):
perl -e 'print join "\n", sort { lc $a cmp lc $b || $a cmp $b } qw( jim JANE jane JIM )'
输出:
JANE
jane
JIM
jim
【讨论】:
虽然这个操作看起来有点矫枉过正,但标准的 Unicode::Collate 和 Unicode::Collate::Locale 模块就是为这种事情而设计的。它们还按字母顺序对非 ASCII 数据进行排序,而普通的 sort 不会这样做。
use utf8;
@names = qw[ jim JANE jane JIM josé josie Mary María mark ];
@sorts = sort @names;
这为您提供了
的排序顺序JANE JIM Mary María jane jim josie josé mark
没有人想要。这好多了:
use utf8;
use Unicode::Collate;
@names = qw[ jim JANE jane JIM josé josie Mary María mark ];
$coll = new Unicode::Collate;
@sorts = $coll->sort(@names);
这给了你
jane JANE jim JIM josé josie María mark Mary
如果你想在小写之前使用大写,请这样指定:
use utf8;
use Unicode::Collate;
@names = qw[ jim JANE jane JIM josé josie Mary María mark ];
$coll = new Unicode::Collate upper_before_lower => 1;
@sorts = $coll->sort(@names);
print "@sorts\n";
产生:
JANE jane JIM jim josé josie María mark Mary
您可以以习惯的方式在一对字符串上使用排序规则对象的 cmp 方法,例如
#!/usr/bin/env perl
use 5.10.1;
use strict;
use autodie;
use warnings qw[ FATAL all ];
use utf8;
use open qw[ :std IO :utf8 ];
use Unicode::Collate;
my @names = qw[ fum fee fie foe ];
my $coll = Unicode::Collate->new;
my @sorts = $coll->sort(@names);
say "@names => @sorts\n";
for (
my($a, $b) = splice @names, 0, 2;
2 == grep {defined} $a, $b;
($a, $b) = ($b, shift @names)
)
{
given ($coll->cmp($a, $b)) {
when (-1) { say "$a < $b" }
when ( 0) { say "$a = $b" }
when (+1) { say "$a > $b" }
default { die "NOT REACHED" }
}
}
产生:
fum fee fie foe => fee fie foe fum
fum > fee
fee < fie
fie < foe
现在考虑这样的单词列表:
sát sot sät sét sæt ssét sat tot ßet SET set seat ſAT ſet saet SSET
如果你在上面运行默认排序,你会得到几乎无用的:
SET SSET saet sat seat set sot ssét sát sät sæt sét tot ßet ſAT ſet
而且区分大小写的排序真的再好不过了:
use utf8;
@names = qw[ sát sot sät sét sæt ssét sat tot ßet SET set seat ſAT ſet saet SSET ];
@sorts = sort {
lc $a cmp lc $b
||
$a cmp $b
} @names;
print "@sorts\n";
产生仍然愚蠢和错误的:
saet sat seat SET set sot SSET ssét sát sät sæt sét tot ßet ſAT ſet
但这里是标准的 Unicode 排序:
use utf8;
use Unicode::Collate;
@names = qw[ sát sot sät sét sæt ssét sat tot ßet SET set seat ſAT ſet saet SSET ];
$coll = new Unicode::Collate upper_before_lower => 1;
@sorts = $coll->sort(@names);
print "@sorts\n";
产生“更正”(阅读:无限优选)版本:
saet sæt sät sat sát ſAT seat SET set sét ſet sot SSET ssét ßet tot
Unicode::Collate 模块非常快,因此您应该毫不犹豫地在您的路线字符排序需求中使用它。但有时这还不够。那是因为不同的语言有不同的字母概念。
顺便说一句,这些也是为什么“将[a-z] 硬编码到你的程序中总是错误的,有时”的很好的例子。它充满了愚蠢甚至侮辱性的假设。 请注意,除了最后三个之外,所有这些实际上都被视为拉丁字母!这与我们在英语中使用的脚本相同。在表示 English 文本时,我不得不处理各种不同的问题:learnèd、Æneid、poſt、Laȝamon、ressumé、1ˢᵗ、MᶜKinley、Van Dijke、Cañon City Colorado、œnology、Dzur、rôle、 ⅷ,首映,比约恩,天真,合作,立面,咖啡馆,Merððyn,考古学,甚至tschüß。重复口头禅:“将[a-z] 硬编码到您的程序中总是错误的,有时。”说不!
Unicode::Collate::Locale 模块处理本地排序约定。就像英语电话簿和书架有特殊的姓名排序方式一样,无论您拼写的是 McBride 还是 MacBride,德语世界也会对其进行排序。 Händel 和 Haendel 的名称相同。这就是为什么没有变音符号,必须强制将 über- 写为 ueber- 并将 Übermensch 写为 Uebermensch。语言环境排序知道这样做:
use utf8;
use Unicode::Collate::Locale;
@names = qw[ sát sot sät sét sæt ssét sat tot ßet SET set seat ſAT ſet saet SSET ];
$coll = new Unicode::Collate::Locale::
locale => de__phonebook,
upper_before_lower => 1,
;
@sorts = $coll->sort(@names);
print "@sorts\n";
现在产生
saet sæt sät sat sát ſAT seat SET set sét ſet sot SSET ssét ßet tot
令人惊讶的是,一个人的语言环境惯例与自己其他国家/地区的语言环境惯例有多么不同。在西班牙语言环境(“es”)中,ñ 是一个出现在 n 之后和 o 之前的字母。这意味着正确的类型
raña rastrillo radio rana rápido ráfaga ranúnculo
是
radio ráfaga rana raña ranúnculo rápido rastrillo
用完全卷起的rr快速地说出所有这些来放松你的舌头。 :)
“es__traditional”语言环境有点不同;从历史上看,chocolate 在西班牙语词典中在 color 之后出现,这与它在英语中的使用方式不同。那是因为ch在c之后d之前,而ll在l之后在 m 之前。这意味着这个序列:
lástima laña llama ligante
cidra caliente color chocolate con churros
pero pera Perú perro periglo peste
排序
caliente cidra color con chocolate churros
laña lástima ligante llama
pera periglo pero perro Perú peste
【讨论】: