2015-01-07 26 views
0

在Perl中,如果你有偶數個元素的列表,你可以直截了當地將其轉換爲一個哈希:的Perl:安全地從列表中進行散列,檢查重複

my @a = qw(each peach pear plum); 
my %h = @a; 

但是,如果有重複鍵那麼他們會被默默接受,而最後一次使用的是它。我想提出一個哈希檢查有沒有重複:

my @a = qw(a x a y); 
my %h = safe_hash_from_list(@a); # prints error: duplicate key 'a' 

顯然,我可以編寫程序自己:

sub safe_hash_from_list { 
    die 'even sized list needed' if @_ % 2; 
    my %r; 
    while (@_) { 
     my $k = shift; 
     my $v = shift; 
     die "duplicate key '$k'" if exists $r{$k}; 
     $r{$k} = $v; 
    } 
    return %r; 
} 

然而,這比簡單的賦值慢得多。此外,如果有CPAN模塊已經完成相同的工作,我不想使用自己的私人例程。

在CPAN上有沒有合適的例程來安全地將列表轉換爲散列?理想情況下,比上面的純Perl實現要快一些(儘管可能不會像簡單分配那麼快)。

如果我可能被允許一個相關的後續問題,我也想知道一個綁定的散列類,它允許每個鍵只被分配一次,並在重新分配時死亡。這將是上述問題的更普遍的情況。再次,我可以自己編寫這樣一個連接的哈希,但我不想重新發明輪子,如果已經存在,我更願意優化實現。

+1

是什麼讓你認爲是慢?我想你會很難找到更快的模塊。你需要對它進行基準測試,我認真地懷疑你會從中獲得很多收益。例如,您可以使用['List :: MoreUtils'' uniq'](https://metacpan.org/pod/List::MoreUtils#uniq-LIST),例如'if(@a == uniq(@a))'。但是這個子程序非常簡單,'sub uniq {我的%看過; grep {!$ seen {$ _} ++} @_; }' – TLP

+0

它可能是最快的,但肯定比簡單賦值%h = @a要慢。測試@a == uniq(@a)沒有做我想做的事情,因爲只有鍵(偶數位元素)需要是唯一的,而不是值。 –

+1

那麼,你會知道'鍵%h'應該等於'@a/2',現在不是嗎? – TLP

回答

2

快速的方法來檢查,沒有鑰匙是重複的將被計數的按鍵,並確保它們等於列表中一半的項目數:

my @a = ...; 
my %h = @a; 
if (keys %h == (@a/2)) { 
    print "Success!"; 
} 
+0

天真的問題:如果ARRAY有奇怪的元素,如'qw/a b c /'? –

+0

然後,你不能強迫它進入哈希首先。 '散列賦值中元素的奇數' – Sobrique

+1

@sputnick然後hash的最後一個值是undef和'warnings'抱怨。 'key%h'是2,'@a/2'是1.5 –