сортировать верхний регистр непосредственно перед строчными значениями ключа из хеша - PullRequest
3 голосов
/ 10 февраля 2011

У меня есть хеш, и я хочу отсортировать его по ключам, в которых прописные слова появляются перед строчными.

Пример:

ДЖЕЙН
Джейн
ДЖИМ
джим

Ответы [ 4 ]

12 голосов
/ 10 февраля 2011

Чтобы привести ключи в порядок, примените 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;

Эта пользовательская функция сортировки сначала сравнивает строки, как если бы они были в одном и том же регистре, и, если они равны, учитывает регистр.

8 голосов
/ 10 февраля 2011

Unicode Collation

Хотя это может показаться излишним для этой операции, стандартные модули 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

Fancier Алфавитные виды Unicode

Теперь рассмотрим список слов, подобных этому:

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

, создающая 'correcter' (читай: бесконечно предпочтительный) версию:

saet sæt sät sat sát ſAT seat SET set sét ſet sot SSET ssét ßet tot

Locale Sorts

Модуль Unicode :: Collate довольно быстрый, поэтому вам не следует стесняться использовать его при сортировке символов маршрута.Но иногда этого просто недостаточно.Это потому, что разные языки имеют разные представления об алфавите.

  • Латинский (архаичный): abcdefzhiklmnopqrstvx
  • Латинский (классический): abcdefghiklmnopqrstvx yz
  • Испанский (традиционный): abcch defghijkl ll mn - opqr rr stuvxwyz
  • Испанский (недавний): abcdefghijklmn - opqrstuvxwyz
  • Каталанский: abc ç defghijklmnopqrstuvxw yz
  • Датский: abcdefghijklmnopqrstu vwxyz ø å
  • Исландский: несколько лет назад
  • Старый английский: abcdef ȝ / ghiklmnopqrstvxyz & ⁊ ƿ þ ð æ
  • Средний английский: abcdefghiklmnopqr ſ / stvxyz ȝ ƿ ð æ
  • Futhorc (транслитерированный ȝ): fueo pxstbeml ŋ d œ ya io cw k st g
  • Греческий: α β γ δ ε η θ ι κ λ μ ν ξ ο π ρ σ / ς τ υ φ χ φ ω
  • Кириллица: а б в г д е ё ж з и й к л м н о п* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Ꮇ Ꮇ Ꮈ Ꮈ Ꮈ Che Che Che Che Che Che Che Ꮈ Ꮈ Ꮈ Ꮈ Ꮈ Ꮈ Ꮈ Ꮈ Ꮈ Ꮈ Ꮈ Ꮈ Ꮊ Ꮊ Ꮊ Ꮊ Ꮊ Ꮊ ᎺᎻ Ꮌ Ꮍ Ꮎ Ꮏ Ꮑ Ꮒ Ꮓ Ꮖ Ꮖ Ꮖ Ꮖ Ꮙ Ꮙ Ꮚ Ꮝ Ꮝ Ꮝ Ꮞ Ꮟ Ꮡ Ꮢ Ꮤ Ꮨ Ꮨ Ꮨ Ꮩ ᏡᏦ10 Ꮾ Ꮿ Ᏸ Ᏹ Ᏺ Ᏻ Ᏼ

Кстати, это также хорошие примеры того, почему «когда-либо жестко кодирует [a-z] в вашей программе всегда неправильно, иногда ». Он полон идиотских и даже оскорбительных предположений. Обратите внимание, что все, кроме последних трех, на самом деле считаются латинскими алфавитами! Это тот же самый скрипт, который мы используем на английском языке.При представлении английского текста мне по-разному приходилось иметь дело с learnèd, Æneid, po ſt, Laȝamon, резюме, 1ˢᵗ, MᶜKinley, Van Dijke, Cañon City Colorado, œnology, Dzur, rôle,,, Премьер, Бьёрн, Наивный, Сотрудничать, Фасад, Кафе, Merððyn, Археология, и даже tschüß .Повторите мантру: «Жесткое кодирование [a-z] в вашей программе всегда неправильно, иногда ». Просто скажите нет!

Модуль Unicode :: Collate :: Locale обрабатывает соглашения о локальной сортировке.Так же, как в английских телефонных книгах и на книжных полках есть особые способы сортировки имен, так что не имеет значения, написали ли вы что-то McBride или MacBride , немецкоязычный мир сортирует их имена так:что Гендель и Гендель одинаковы.Вот почему без диакритики нужно обязательно написать ü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

Se habla castellano

Удивительно, как отличается от своегорегиональные соглашения других стран могут быть.В испанском языке («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" немного отличается;исторически, шоколад пришел после color в испанском словаре, в отличие от того, как это работает на английском языке.Это потому, что ch пришел после c и до d , в то время как ll пришел после l и до м .Это означает, что эта последовательность:

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
8 голосов
/ 10 февраля 2011

Используйте пользовательскую сортировку, которая сначала сравнивает элементы на основе их представлений в нижнем регистре (так что все варианты «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
6 голосов
/ 10 февраля 2011

Попробуйте:

@list = ("jane","JIM","JANE","jim");
print sort { uc $a cmp uc $b or $a cmp $b } @list;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...