2010-09-08 85 views
-2

予有這種如何在Perl中同時刪除重複項和排序?

@uniqarr = qw(error 0 goodrecordno:6123, error 0 goodrecordno:6143, error 1 goodrecordno:10245, error 1 goodrecordno:10678, error 1 goodrecordno:10698, error 2 goodrecordno:16245, error 2 goodrecordno:16123); 

我想要的O/P的陣列作爲

error 0 goodrecordno:6123 
error 1 goodrecordno:10245 
error 2 goodrecordno:16123 

即與其相應的最低recordno每個錯誤一次性。 誰能幫我沒有使用CPAN模塊提前

感謝。

+3

Hunh?發佈Stack Overflow是爲了支付專家網站的替代方案時請記住。使用神祕的速記來表明你的問題不可能在將來幫助任何人。該數組將被稱爲'@ uniqarr',除非你想要一個名爲'goodrecord:6123','(*帶鍵*中的逗號)的鍵,否則不應該將逗號放在'qw()'列表中。什麼是「o/p」? *輸出*?您可以以輸入* 4 *多餘字符爲代價節省大量的困惑。 – Axeman 2010-09-08 20:19:43

+2

「不使用CPAN模塊」?爲什麼? – Ether 2010-09-08 20:22:54

+0

對不起老闆...!我試圖學習編寫沒有cpan模塊的每個程序。所以我只想要它沒有它們,因爲它們可能使用cpan模塊很簡單。我想從基礎學習核心邏輯。時間起點,我會明確寫下所有內容。感謝您的建議和意見。 – Sunny 2010-09-08 20:34:33

回答

3

這是你在開始Perl書籍找到基本的最小最大問題。你通過所有元素並記住哪一個是最低的。這比排序要好得多,這是爲了讓你把所有的元素排列好而已,這不是你所追求的。

use strict; 
use warnings; 

# I'll assume those commas were a mistake. You don't need to separate 
# items with commas in a quotewords list 
# If I'm wrong, the process is the same although the data massaging 
# will be a little different 
my @elements = qw(
    error 0 goodrecordno:6123 
    error 0 goodrecordno:6143 
    error 1 goodrecordno:10245 
    error 1 goodrecordno:10678 
    error 1 goodrecordno:10698 
    error 2 goodrecordno:16245 
    error 2 goodrecordno:16123 
    ); 

my %lowest; 
while(my($error, $number, $goodrecno) = splice @elements, 0, 3,()) 
    { 
    my($recno) = $goodrecno =~ /(\d+)/; 

    # This hash remembers the lowest $recno. If you find another 
    # a lower number, you replace the previous value. 
    $lowest{$number} = $recno if( 
     ! exists $lowest{$number} 
      || 
     $recno < $lowest{$number} 
     ); 
    } 

一旦你創建具有最低元素的哈希,你只是打印:

foreach my $number (sort { $a <=> $b } keys %lowest) { 
    print "error $number goodrecordno:$lowest{$number}\n"; 
    }; 

這個給你,你要找的輸出:

error 0 goodrecordno:6123 
error 1 goodrecordno:10245 
error 2 goodrecordno:16123 

這是這些問題的基本模板。第1步:掃描數據以記住您想要的內容,使用散列來鍵入這些數據。第2步:輸出散列的內容。

1

要刪除重複,最好的辦法是使用List::MoreUtilsuniq,:

use List::MoreUtils 'uniq'; 
my @unique_list = uniq @list; 

或不CPAN(雖然這是很少有必要):

my %values; 
@values{@list} =(); 
my @unique_list = keys %values; 

您可以按任何列表使用內置函數排序 - 見perldoc -f sortperldoc -q 'How do I sort an array'


順便提一下,您引用的數據與您描述的行爲不匹配。如果聲明數組作爲

@uniqarr = qw(error 0 goodrecordno:6123, error 0 goodrecordno:6143, error 1 goodrecordno:10245, error 1 goodrecordno:10678, error 1 goodrecordno:10698, error 2 goodrecordno:16245, error 2 goodrecordno:16123); 

...那麼它的內容將包括:

(
    'error', 
    '0', 
    'goodrecordno:6123,', 
    'error', 
    '0', 
    'goodrecordno:6143,', 
    'error', 
    '1', 
    'goodrecordno:10245,', 
    'error', 
    '1', 
    'goodrecordno:10678,', 
    'error', 
    '1', 
    'goodrecordno:10698,', 
    'error', 
    '2', 
    'goodrecordno:16245,', 
    'error', 
    '2', 
    'goodrecordno:16123' 
); 

你需要做的是閱讀的數據轉換成哈希表什麼,然後根據解析你的標準。我不能進一步,因爲它不是很清楚你在找什麼。請閱讀perldoc perldataperldoc perldsc更多地瞭解Perl數據結構。

+0

您只關心鍵,'@values {@list} =();'更快,佔用內存更少。 – 2010-09-08 20:48:01

+0

@Chas:很好;我沒有意識到,沒有相同長度的RHS列表,散列片就可以工作。 – Ether 2010-09-08 20:50:57

+0

你不想排序。這對於這個問題來說太麻煩了。我不明白這個答案是如何解決問題的。獨特的元素在這裏沒有任何幫助。 – 2010-09-08 20:52:52

0

正如其他人已經指出了你的第一個問題是:qw()是不恰當的,建立這個數組。

有很多方法可以正確地做到這一點,我打算在這裏使用一個哈希數組,這是一個更加詳細的選項,將該技術修改爲您選擇的任何結構相當容易。


@uniqarr = (
    { error => 0, goodrecordno => 6123, }, 
    { error => 0, goodrecordno => 6143, }, 
    { error => 1, goodrecordno => 10245, }, 
    { error => 1, goodrecordno => 10678, }, 
    { error => 1, goodrecordno => 10698, }, 
    { error => 2, goodrecordno => 16245, }, 
    { error => 2, goodrecordno => 16123, }, 
); 

然後提取每個錯誤實例與最低goodrecordno我們可以做到以下幾點。

首先我們從List :: Util導入min。該模塊是核心Perl,不需要CPAN。

然後重構輸入@uniqarr。對於我們想要通過錯誤值進行分組,這更容易。所以by_error是數組的散列。散列的關鍵是錯誤值,該數組包含所有goodrecordno值。

最後我們產生所需的輸出。通過哈希循環意味着我們遍歷每個錯誤值,進行排序以提供正確的輸出順序。然後我們提取最小的goodrecordno值。這只是打印輸出。


use List::Util qw(min); # In core Perl, not CPAN 

# Restructure input 
my %by_error; # Hash with error as key, array of goodrecordno as value. 
foreach (@uniqarr) { 
    push @{$by_error{$_->{error}}}, $_->{goodrecordno}; 
} 

# Output as desired 
foreach my $error (sort keys %by_error) { 
    my $min_no = min @{$by_error{$error}}; 
    print "error $error goodrecordno:$min_no\n"; 
}