簡體   English   中英

Perl將File拆分為數組並從子例程讀取

[英]Perl splitting File into array and reading from subroutine

我已經創建了一個子程序,該子程序從下面提供的選項卡中創建了HoA。

header_map.txt:

account_number_header   account
account_number_header   Account #
account_number_header   Account No.
account_number_header   Account number
account_number_header   Account_Id
first_Name_header   name1
first_Name_header   first name
first_Name_header   account name1
first_Name_header   first_name
first_Name_header   f name
last_Name_header    name2
last_Name_header    last name
last_Name_header    account name2
last_Name_header    last_name
last_Name_header    l name
address_header  address1
address_header  address
address_header  addresses
address_header  place of residency
address_header  location

子然后將數組從給定鍵的值反彈(如下所示)。 如果值與數組匹配,則返回匹配數組元素的索引。 我要執行的操作不是搜索預定義的常量數組,而是要搜索從文件或在這種情況下為數據讀取的數組。 常量數組的工作代碼如下。

my @fields = ('Account No.','name1','name2','location'); #array being searched
my $hm = "header_map.txt"; #declare variable to file
my $fh = (readfile($hm));  #declare variable to sub routine call

my $address_header = 'address_header'; #my given key
my $address = hashofarray($fh,$address_header); #looking for($fh,key) in sub
my $account_number_header = 'account_number_header'; #my given key
my $account_number = hashofarray($fh,$account_number_header); #looking for($fh,key) in sub
print $address,",",$account_number,"\n"; #prints desired array indexes of given keys

sub hashofarray {
    my $fh = shift;
    my $key = shift;
    my %hash;
    while (<$fh>) { # creating HoA
        chomp;
        my ( $key, $value  ) = split /\t/;
        push (@{ $header_map{$key} }, $value);
    }
    foreach my $key1 (@{$header_map{$key}}) {
        if (my @index = grep { $fields[$_] eq $key1 } 0..$#fields) {
            return $index[0];
        }
    }
}

sub readfile {
    my $file = shift;
    open my $f, '<', $file or die $!;
    return $f;
}

結果

location,Account No.

這很好,也是我想要的,但是我想改為從DATA文件讀取數組@fields。 這是我在讀取DATA時的嘗試。

嘗試失敗

my $hm = "O:/josh/trade_data/mock_header_map.txt"; # declare variable to file
my $fh = (readfile($hm)); # declare variable to sub routine call

while (<DATA>) { # calling the subroutine after reading DATA
    my @fields = split /\t/;
    my $address_header = 'address_header'; # my given key
    my $address = hashofarray($fh, $address_header); # looking for($fh, key) in sub
    my $account_number_header = 'account_number_header'; # my given key
    # looking for($fh, key) in sub
    my $account_number = hashofarray($fh, $account_number_header);
    # prints desired array indexes of given keys
    print $address, ",", $account_number, "\n";
}

sub hashofarray {
    my $fh = shift;
    my $key = shift;
    my %hash;
    while (<$fh>) {  #creating HoA
        chomp;
        my ( $key, $value  ) = split /\t/;
        push (@{ $header_map{$key} }, $value);
    }
    foreach my $key1 (@{$header_map{$key}}) {
        if(my @index = grep { $fields[$_] eq $key1 } 0..$#fields) {
            return $index[0];
        } else {
            print "not found";
        }
    }
}

sub readfile {
    my $file = shift;
    open my $f, '<', $file or die $!;
    return $f;
}


__DATA__
Account No  name1   name2   location
1   josh    smith   411 s chirris ave. sometown st 12345
1   josh    smith   411 s chirris ave. sometown st 12345
1   josh    smith   411 s chirris ave. sometown st 12345
1   josh    smith   411 s chirris ave. sometown st 12345

我的結果

,
,
,
,
,

所需結果

1   411 s chirris ave. sometown st 12345
1   411 s chirris ave. sometown st 12345
1   411 s chirris ave. sometown st 12345
1   411 s chirris ave. sometown st 12345

最后,我想打印所需的列,如果我可以將DATA讀取到數組中的話,我可以這樣做,但是我得到的是空字符串,因為該子程序無法識別@fields。 我知道我需要對數組引用進行一些操作,但是我對那些引用有一點建議。 我希望這很清楚。

好吧 這里的核心問題是您的hashofarray函數嘗試讀取文件句柄。 然后,您迭代到文件末尾。 然后...當沒有更多文件可讀取時,您再次調用它。

但這不是這里唯一的問題-有幾個。 如果您要從數組的哈希中提取鍵...為什么不使用哈希哈希呢? 執行此操作的方式 -有效地-通過數組進行搜索,但是無論如何都返回零索引。

同樣- @fields不在全局范圍內,因此,當您嘗試在hashofarray重用它時,它總是空的。

我可以建議退后一步嗎? 使用您的實際問題規范更新您的問題(或提出一個新問題)? 包括輸入數據和預期輸出。

我認為您已經經歷了幾個修復此代碼的周期,而且變得一團糟,所以我認為是時候退后一點並重新開始了。 我認為您會發現有很多更清潔,更優雅的解決方案。

就是說-如果您只是想從現有數據塊中提取“標題”行:

my @fields = split /\t/,<DATA>; #read first line, split into array. 
while ( <DATA> ) { #etc.

例如,您可以將“數據”部分轉換為如下數據結構:

use strict;
use warnings;
use Data::Dumper;
my @all_records;
my $header_line = <DATA>;
chomp($header_line);
my @headers = split /\t/, $header_line;
while (<DATA>) {
    chomp;
    my @columns = split /\t/;
    my %record;
    @record{@headers} = @columns;
    print Dumper \%record;
    push( @all_records, \%record );
}

print Dumper \@all_records;

foreach my $record ( @all_records ) { 
   print join ",", $record -> {'Account No'}, $record -> {'location'},"\n";
}

__DATA__
Account No  name1   name2   location
1   josh    smith   411 s chirris ave. sometown st 12345
1   josh    smith   411 s chirris ave. sometown st 12345
1   josh    smith   411 s chirris ave. sometown st 12345
1   josh    smith   411 s chirris ave. sometown st 12345

不過,我建議-您可以將“帳號”用作唯一鍵,可能因此實際上不需要使用數組。 不過,在這種情況下,您需要這樣做,所以我已經在代碼中做到了。

這將打印:

1,411 s chirris ave. sometown st 12345,
1,411 s chirris ave. sometown st 12345,
1,411 s chirris ave. sometown st 12345,
1,411 s chirris ave. sometown st 12345,

您正在使用我的內部while循環聲明@fields

while (<DATA>) { # calling the subroutine after reading DATA
my @fields = split /\t/;

因此,該變量的范圍僅在while循環中。 與其嘗試這樣做, @fields在while循環上方聲明數組@fields

另外,請將這些放在您的代碼頂部。

use strict;
use warnings;

如果這些行位於頂部,您將發現此錯誤。

另外,您還需要改善讀取文件的方式。 首次讀取$fh時,尋道指針將最后到達,此后您的代碼將永遠不會從文件中讀取任何內容。 它將在第一次迭代中創建的哈希上工作。 因此,如果一次讀取一個文件足以滿足您的需要,那么如果您想一次又一次地閱讀,請將該閱讀部分從其他部分中刪除,然后關閉$fh並再次重新打開它。

if(my @index = grep { $fields[$_] eq $key1 } 0..$#fields) {將不會從實際給予字@fields反而會給匹配的詞從指數@fields所以在印刷時這應該被使用

print $fields[$address],",", $fields[$account_number], "\n";

希望這些更改之后,您將能夠為您的問題寫出正確的解決方案。

暫無
暫無

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

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