2012-10-25 61 views
5

我使用模塊List :: MoreUtils導出的uniq函數來查找數組中的uniq元素。但是,我希望它以不區分大小寫的方式查找uniq元素。我怎樣才能做到這一點?Perl中不區分大小寫的獨特數組元素

我有傾倒的陣列的使用Data ::自卸車的輸出:

#! /usr/bin/perl 

use strict; 
use warnings; 
use Data::Dumper qw(Dumper); 
use List::MoreUtils qw(uniq); 
use feature "say"; 

my @elements=<array is formed here>; 

my @words=uniq @elements; 

say Dumper \@words; 

輸出:

$VAR1 = [ 
      'John', 
      'john', 
      'JohN', 
      'JOHN', 
      'JoHn', 
      'john john' 
     ]; 

預期輸出應爲:約翰,約翰約翰

只有2個元素,所有休息都應該過濾,因爲它們是同一個詞,只是區別是如此。

如何刪除忽略大小寫的重複元素?

回答

9

使用小寫,lcmap聲明:

my @uniq_no_case = uniq map lc, @elements; 

原因List::MoreUtils'uniq是區分大小寫的是它依賴於哈希的重複數據刪除特性,這也是區分大小寫。對於uniq代碼看起來像這樣:

sub uniq { 
    my %seen =(); 
    grep { not $seen{$_}++ } @_; 
} 

如果你想直接在自己的代碼中使用此子,你可以在那裏整合lc

sub uniq_no_case { 
    my %seen =(); 
    grep { not $seen{$_}++ } map lc, @_; 
} 

是如何工作的說明:

@_包含子程序的參數,並將它們輸入到grep語句中。任何通過代碼塊返回true的元素都由grep語句返回。代碼塊由幾個更精細的點組成:

  • $seen{$_}++第一次看到元素時返回0。該值仍然增加到1,但返回後(與++$seen{$_}相反,誰先增加,然後返回)。
  • 通過否定增量結果,我們對第一個鍵成立,對於每個後面的這個鍵成立假。因此,該列表被重複。
  • grep作爲sub中的最後一個語句將返回一個列表,而這個列表又是由sub返回的。
  • map lc, @_只是將lc函數應用於@_中的所有元素。
+0

這和List :: MoreUtils模塊導出的uniq函數是一樣的嗎? –

+0

確實如此。雖然由於sub是如此簡單而短小,你可以複製粘貼它,並保存自己加載模塊。 – TLP

+0

謝謝。我會理解子程序,然後直接使用它:)你能解釋一下grep語法嗎?哈希%顯示使用數組的元素作爲關鍵字並檢查它們的出現。但是,我不確定,這整個語法是如何工作的。 –

6

使用哈希來跟蹤你已經看到了的話,也歸他們大/小寫:

my %seen; 
my @unique; 
for my $w (@words) { 
    next if $seen{lc($w)}++; 
    push(@unique, $w); 
} 
# @unique has the unique words 

注意,這將保留原話的情況。

更新:正如註釋中所述,目前尚不清楚OP的需求,但我以這種方式編寫了解決方案,以說明在某種「等價關係」下從列表中選擇唯一代表的一般技術。在這種情況下,等價關係是字$a相當於字$b當且僅當lc($a) eq lc($b)

大多數等價關係,可以通過這種方式來表達,那就是,這種關係是由分類函數定義f()這樣$a相當於$b當且僅當f($a) eq f($b)。例如,如果我們想說如果兩個單詞具有相同的長度,那麼它們是相同的,那麼f()將是length()

所以現在你可能會看到爲什麼我這樣寫了算法 - 分類器函數可能不會產生屬於原始列表的一部分的值。在f = length的情況下,我們要選擇單詞,但一個單詞的f是一個數字。

+0

在散列訪問中使用'lc'比給出的其他解決方案好得多,因爲它保留了輸入中的(第一個匹配)情況。 – LeoNerd

+0

@LeoNerd你究竟在說什麼?在散列之前和之間使用lc沒有區別。 – TLP

+0

我的意思是,與其他答案中給出的映射lc ...解決方案相反。這個更好,因爲它在原始情況下返回值,而不是強迫 - 小寫。 – LeoNerd