2013-03-14 45 views
1

我有以下文件:迭代一個簡單的程序

a b 5 
c d 6 
e f 7 
g h 4 
i j 3 
k l 10 

和我想找到哪一行呈現最小值在第三列和從初始文件擦除。在此之後,我想再次迭代該程序,並再次找到哪一行呈現最小值,並再次進行2次相同的操作。

輸出文件應該是

c d 6 
e f 7 
k l 10 

我試着寫了下面的代碼:

#!/usr/bin/perl 

use strict; 
use warnings; 
use feature 'say'; 

my $file1 = "try.dat"; 
open my $fg, "<", $file1 or die "Error during $file1 opening: $!"; 

my @vector; 

while (<$fg>) { 
    push @vector, [ split ]; 
} 

my $minimum = $vector[0][2]; 
my @blacklist; 
for my $i (0 .. $#vector) { 
    if ($minimum > $vector[$i][2]){ 
    $minimum = $vector[$i][2]; 
    push @blacklist, @vector[$i+1]; 
    } 
} 
#say "my minimum is $minimum"; 
#say "the blacklist is composed by @blacklist"; 

我不知道如何以擦除首先由@blacklist(包含的元素案例應該是i j 3)以及如何迭代一切。

迭代的任何幫助?

回答

1

當你說@blacklist = @vector你正在將整個@vector數組添加到黑名單。你可能想要做一個push @blacklist, $vector[$i]。這會將數組引用推入黑名單。

現在,黑名單中有一個數組ref,所以你必須遵守它來打印它。

say "the blacklist is composed by @{$blacklist[0]}"; 

編輯:對於迭代和寫作:

我會跳過@blacklist陣列(除非你需要它別的東西),並從@vector刪除最小值。然後你可以寫@vector到某個文件。

my $num_elts_to_remove = 3; 
for (my $j = 0; $j < $num_elts_to_remove; $j++) { 
    my $minimum = $vector[0][2]; 
    my $min_idx = 0; 
    for my $i (0 .. $#vector) { 
     if ($minimum > $vector[$i][2]){ 
     $minimum = $vector[$i][2]; 
     $min_idx = $i; 
     } 
    } 
    push @blacklist, $vector[$min_index]; 
    splice @vector, $min_idx, 1; #remove array with smallest value 
} 

現在陣列寫入一個文件

open OUT, ">", $outfile or die "Error: $!"; 
foreach(@vector) { 
    print OUT join " ", @$_; 
    print OUT "\n"; 
} 
close(OUT); 

打印:

c d 6 
e f 7 
k l 10 
+0

你應該編輯推'@blacklist,$ vector [$ i + 1]'並且它可以工作。關於如何擦除文件中的行並迭代它的任何想法? – 2013-03-14 17:26:01

+0

在'splice @vector,$ min_idx,1;'這一行是什麼意思?如果我想使用「黑名單」數組,我該怎麼辦?如果($ minimum> $ vector [$ i] [2]){\ i = 0 [$ i] [2]),我嘗試了'爲我的$ i(0.. $#向量){0}。 push @blacklist,@vector [$ i + 1]; } } splice @vector,@blacklist;'但它不起作用 – 2013-03-15 08:45:48

+0

'1'是長度或要移除的元素的數量。請參閱[文檔](http://perldoc.perl.org/functions/splice.html)。如果你想保留一個黑名單,在拼接前先推它。 (見編輯)。 'push @blacklist,$ vector [$ min_index];' – Nate 2013-03-16 02:51:10

2

這樣的事情是什麼Tie::File被造的。它允許您通過修改綁定數組來修改文件。

這個程序做你想做的。幫助函數minidx返回保存最小值的傳遞數組元素的第一個索引。

該程序的工作原理是將文件記錄的第三個字段複製到數組@field3中,並找到那裏最小值的索引。然後使用splice從該文件和@field3中刪除該索引處的元素。

use strict; 
use warnings; 

use Tie::File; 

tie my @file, 'Tie::File', 'file.txt' or die $!; 

my @field3 = map { (split)[2] } @file; 
for (1 .. 3) { 
    my $i = minidx(\@field3); 
    splice @file, $i, 1; 
    splice @field3, $i, 1; 
} 

sub minidx { 
    my ($arr) = @_; 
    my ($i, $v); 
    for (0 .. $#$arr) { 
    ($i, $v) = ($_, $arr->[$_]) unless defined $v and $arr->[$_] >= $v; 
    } 
    return $i; 
} 

輸出

c d 6 
e f 7 
k l 10 
+0

我可以幫你解決你的問題。所以很少有人喜歡Tie :: File,所以我想你可能也會喜歡我的回答,它會在引擎蓋下使用它。 – 2013-03-16 03:54:13

0

以鮑羅廷的領帶::文件建議更進一步。我寫了一個名爲Tie::Array::CSV的可愛模塊,它允許你將一個分隔文件當作一個數組來處理(因爲它在下面使用Tie :: File,它是可讀寫的)。正因爲如此,我可以用Perl化的操作,如地圖和排序(和使用Schwartzian變換!)來執行此任務:

#!/usr/bin/env perl 

use strict; 
use warnings; 

use Tie::Array::CSV; 

tie my @data, 'Tie::Array::CSV', 'data', sep_char => ' '; 

# get a list of row ids sorted by last value (inc) 
my $i = 0; 
my @sorted = 
    map { $_->[0] } 
    sort { $a->[1] <=> $b->[1] } 
    map { [$i++, $_->[-1]] } 
    @data; 

#splice the rows by index of the lowest three (from bottom to top) 
splice @data, $_, 1 for reverse sort @sorted[0..2]; 

注意,你到底想從底部刪除行,這樣你就不必每次重新索引。