Как я могу поддерживать порядок ключей, которые я добавляю к хэшу Perl?
Как я могу сохранить порядок фактического списка после подсчета его появления, используя хеш в следующей программе? Например, <DATA>
являются
a
b
e
a
c
d
a
c
d
b
etc.
Используя hash, я подсчитал появление каждого элемента.
и я хочу:
a 3
b 2
e 1
c 2
d 2
но следующая программа показывает мне в противном случае.
my (%count, $line, @array_1, @array_2);
while ($line = <DATA>) {
$count{$line}++ if ( $line =~ /\S/ );
}
@array_1 = keys(%count);
@array_2 = values(%count);
for(my $i=0; $i<$#array_1; $i++)
{
print "$array_1[$i]\t $array_2[$i]";
}
Ответы
Ответ 1
Хэши не упорядочены, но, как обычно, CPAN предлагает решение: Tie:: IxHash
use Tie::IxHash;
my %count;
tie %count, 'Tie::IxHash';
while ($line = <DATA>) {
$count{$line}++ if ( $line =~ /\S/ );
}
while( my( $key, $value)= each %count) {
print "$key\t $value";
}
Ответ 2
Данные в хэш-таблице хранятся в порядке хэш-кода ключей, который для большинства целей подобен случайному порядку. Вы также хотите сохранить порядок первого появления каждого ключа. Вот один из способов решения этой проблемы:
my (%count, $line, @display_order);
while ($line = <DATA>) {
chomp $line; # strip the \n off the end of $line
if ($line =~ /\S/) {
if ($count{$line}++ == 0) {
# this is the first time we have seen the key "$line"
push @display_order, $line;
}
}
}
# now @display_order holds the keys of %count, in the order of first appearance
foreach my $key (@display_order)
{
print "$key\t $count{$key}\n";
}
Ответ 3
От perlfaq4 ответ на Как я могу сделать свой хэш помните, как я вставлял в него элементы?
Как я могу сделать свой хэш, помню порядок, в который я вставлял элементы?
Используйте Tie:: IxHash из CPAN.
use Tie::IxHash;
tie my %myhash, 'Tie::IxHash';
for (my $i=0; $i<20; $i++) {
$myhash{$i} = 2*$i;
}
my @keys = keys %myhash;
# @keys = (0,1,2,3,...)
Ответ 4
Просто:
my (%count, @order);
while(<DATA>) {
chomp;
push @order, $_ unless $count{$_}++;
}
print "$_ $count{$_}\n" for @order;
__DATA__
a
b
e
a
c
d
a
c
d
b
Или как вкладчик
perl -nlE'$c{$_}++or$o[@o]=$_}{say"$_ $c{$_}"[email protected]'<<<$'a\nb\ne\na\nc\nd\na\nc\nd\nb'
Ответ 5
Другим вариантом является метод David Golden (@xdg) простой чистый perl Hash::Ordered
. Вы получаете заказ, но он медленнее, поскольку хеш становится объектом за кулисами, и вы используете методы для доступа и изменения элементов хэша.
Есть, вероятно, тесты, которые могут количественно определить, насколько медленнее модуль, чем обычные хэши, но это классный способ работать с структурами данных ключевых/значений в небольших сценариях и достаточно быстро для меня в этом виде приложения. В документации упоминается несколько других подходов к упорядочению хэша.
Ответ 6
Я не уверен, что это всегда лучший метод, но я использовал его иногда. Вместо того, чтобы иметь только "видимый" тип хеша, он может хранить как подсчет, так и порядок.
В принципе, вместо $count{$line}
, имеющего число раз увиденное, $count{$line}{count}
- это время и $count{$line}{order}
- это порядок, в котором он был замечен.
my %count;
while (my $line = <DATA>) {
chomp $line;
if ($line =~ /\S/) {
$count{$line} ||= { order => scalar(keys(%count)) };
$count{$line}{count}++;
}
}
for my $line (sort { $count{$a}{order} <=> $count{$b}{order} } keys %count ) {
print "$line $count{$line}{count}\n";
}
Ответ 7
Хэши - это просто массивы до тех пор, пока они не будут назначены в Perl, поэтому, если вы приведете их в виде массива, вы можете перебрать их в исходном порядке:
my @array = ( z => 6,
a => 8,
b => 4 );
for (my $i=0; $ar[$i]; ++$i) {
next if $i % 2;
my $key = $ar[$i];
my $val = $ar[$i+1];
say "$key: $val"; # in original order
}
Вы потеряете преимущества хеширования, если сделаете это явно. Но поскольку хеш - это просто массив, вы можете создать его, просто назначив массив хешу:
my %hash = @array;
say $hash{z};
Возможно, это всего лишь вариант решения "использовать массив в качестве индекса", но я думаю, что оно более аккуратное, потому что вместо того, чтобы печатать свой индекс вручную (или каким-либо другим способом), вы создаете его непосредственно из исходного массива.