Почему хеш-ключи имеют другой порядок при печати?
Я хочу создать несколько хэшей, используя одни и те же ключи, и чтобы ключи печатались одинаково. Итак, в приведенном ниже примере ключи $hash1
а также $hash2
должен всегда иметь один и тот же порядок, но при создании хэша не должно быть необходимости сохранять этот порядок.
use Data::Dumper;
my $hash1 = {
keyc => 2,
key1 => 1,
keya => 3,
keyb => 4,
};
my $hash2 = {
keyc => 2,
key1 => 1,
keya => 3,
keyb => 4,
};
print Dumper $hash1, $hash2;
Но вывод выглядит следующим образом:
$VAR1 = {
'key1' => 1,
'keyc' => 2,
'keyb' => 4,
'keya' => 3
};
$VAR2 = {
'keyb' => 4,
'keya' => 3,
'keyc' => 2,
'key1' => 1
};
то есть хэши имеют другой и неожиданный порядок. Что не так с моим Perl?
Моя версия Perl:
This is perl 5, version 18, subversion 2 (v5.18.2) built for darwin-thread-multi-2level
(with 2 registered patches, see perl -V for more detail)
Обратите внимание: я знаю, что ключи хэша perl не отсортированы. Я хочу, чтобы у них был один и тот же порядок, но не нужно иметь отсортированный порядок. Я надеюсь, что смогу получить такой же вывод на печать, если снова запусту код.
Следуя советам из ответов, я установил две переменные среды:
PERL_HASH_SEED=0x00 PERL_PERTURB_KEYS=0
Тогда я могу получить тот же вывод, когда я запускаю код повторно.
3 ответа
При печати хэша есть несколько различных понятий порядка: "порядок вставки", "порядок сортировки" и "случайный". Смотрите раздел ОКРУЖАЮЩАЯ СРЕДА perlrun
документация для обсуждения способов, которыми вы можете управлять этим поведением, а также причин, по которым по умолчанию используется хэширование.
В течение по крайней мере десятилетия хэши в perl не гарантировали порядок ключей. В последнее время рандомизация хэшей была частью общей меры по усилению безопасности. Есть веские причины для рандомизации хэшей. Для более подробной информации смотрите perlsec
обсуждение алгоритмической сложности атак. В документации по безопасности Perl вы заметите, что в perl-5.18
- если вы видите другое поведение по сравнению с предыдущими версиями, это может быть связано с этими последними изменениями.
Помимо явной сортировки ваших ключей хеша, существуют и другие подходы, которые вы можете использовать для упорядочивания ваших хэшей: Hash::Ordered
это один пример. Hash::Ordered
В документации есть хорошее обсуждение плюсов и минусов ряда других модулей.
В то время как хеш - это " неупорядоченная корзина " скаляров, расположенных в парах ключ-значение; массив - это " упорядоченная последовательность " скаляров [ 1 ]. " Срез " - это способ одновременного доступа к "нескольким элементам списка, массива или хэша". Срез использует @
sigil, так как операция возвращает список из нескольких значений - и с @
мы получаем "упорядоченную последовательность". В результате один из способов наложения своего рода "порядка" на хеш - это использование для доступа к нему фрагмента:
# We want alphabetical disorder ...
my %hashed = ( 1 => "z", 2 => "x", 3 => "y" );
for my $key ( keys %hashed ) { print $hashed{$key} } ;
__END__
zyx
Мы хотим " zxy
"не" zyx
". Чтобы наложить нашу произвольную версию порядка на этот хеш, мы сначала должны признать, что виновник здесь keys %hashed
который возвращает ключи в случайном порядке. Решение состоит в том, чтобы sort
ключи Ccurse и в этом надуманном примере мы храним их в @sort_order
и использовать его, чтобы "вырезать" то, что мы хотим из хэша, так, как мы этого хотим:
my @sort_order = sort keys %hashed ;
print @hashed{@sort_order} ;
__END__
zxy
Тада!! Срезы могут быть полезны, когда вы хотите хранить ключи и значения в хэше, но обращаться к этим данным упорядоченным способом. Помните " @
"когда вы хотите нарезать хеш; как perldata
ставит это: "вы используете '@'
... на срез хеша... [потому что вы получаете... список ". И списки упорядочены.
[ 1 ] Определения хэшей как "неупорядоченных корзин" и массивов как "упорядоченной последовательности" взяты из превосходной статьи Майка Фридмана (FRIEDO) о массивах и списках в Perl.
Дальнейшие ссылки
- ср
perlfaq
-q Как мне всегда хранить мой хэш отсортированным? - В дополнение к созданию ряда действительно полезных модулей CPAN, GARU (Брено де Оливейра) опубликовал отличную статью по упорядочиванию хеша, которая подробно освещает недавние проблемы разработки на Perl и рандомизации хешей.
- Для более продвинутых примеров изящных вещей, которые вы можете сделать с кусочками хеша, см. Статью Винса Веселоского. Хеш-кусочки могут заменить циклы.
Ничего плохого в вашем Perl, хэш не отсортирован.
Если вы хотите отсортировать по ключу, вам нужно сделать что-то вроде этого:
foreach my $key (sort keys %hash1) {
print $key, $hash1{$key};
}
и то же самое для hash2...
Г. Чито ответ правильный. Если вы хотите отсортированный вывод из Data::Dumper, вы можете сделать:
use Data::Dumper;
my $hash1 = {
keyc => 2,
key1 => 1,
keya => 3,
keyb => 4,
};
my $hash2 = {
keyc => 2,
key1 => 1,
keya => 3,
keyb => 4,
};
my $dumper = Data::Dumper->new([$hash1, $hash2]);
$dumper->Sortkeys(1);
print $dumper->Dump;