簡體   English   中英

如何維護我添加到Perl哈希的鍵的順序?

[英]How can I maintain the order of keys I add to a Perl hash?

如何在使用以下程序中的哈希計算實際列表的順序后維護實際列表的順序? 例如, <DATA>

a
b
e
a
c 
d 
a
c
d
b
etc.

使用哈希,我計算每個元素的出現次數。

我想要的是:

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

哈希不是訂購的,但像往常一樣,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"; 
}

散列表中的數據按密鑰的散列碼的順序存儲,對於大多數目的而言,其類似於隨機順序。 您還希望存儲每個鍵的第一個外觀的順序。 這是解決此問題的一種方法:

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

perlfaq4的回答“如何讓我的哈希記住我將元素放入其中的順序?”


如何讓哈希記住我將元素放入其中的順序?

使用CPAN中的Tie :: IxHash。

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,...)

只是:

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

或者作為oneliner

perl -nlE'$c{$_}++or$o[@o]=$_}{say"$_ $c{$_}"for@o'<<<$'a\nb\ne\na\nc\nd\na\nc\nd\nb'

另一種選擇是David Golden的(@xdg)簡單的純perl Hash::Ordered模塊。 您獲得了順序,但它更慢,因為哈希成為幕后的對象,您使用方法來訪問和修改哈希元素。

可能的基准測試可以量化模塊比常規哈希值慢多少,但它是一種很酷的方式,可以在小腳本中使用鍵/值數據結構,並且在這種應用程序中足夠快。 該文檔還提到了其他幾種排序哈希的方法。

我不相信這總是一種更好的技術,但我有時會用它。 它可以存儲注意到的計數和順序,而不僅僅是具有“看到”類型的哈希。

基本上,代替$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";
}

散列只是數組,直到它們在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};

這可能只是“使用數組作為索引”解決方案的變體,但我認為它更整潔,因為不是手動(或以其他方式)鍵入索引,而是直接從源數組創建它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM