【问题标题】:Perl: duplicate keys not overwriting in hashPerl:重复的键不会在哈希中覆盖
【发布时间】:2016-11-15 23:29:45
【问题描述】:

我有一个问题,我似乎找不到答案。

我有一个 CSV 文件,其中包含不同个人的绩效记录。假设每个人只有一条记录,但是,有些人有几条不同信息的记录。我想将第一个文件与另一个也有个人列表的文件进行比较,尽管我只想比较文件 1 中的个人是否在文件 2 中也有记录(文件 2 没有重复项)。个人 ID 是唯一的。

文件 1 的示例:

ID number      A       B     C            D
4011NM16001    apple   24    sunday       2016-01-01
4011NM16001    apple   16    wednesday    2016-01-01
4012NM15687    pear    16    sunday       2015-04-19
4012NM15002    banana  8     monday       2015-09-09
4012NM14301    peach   10    wednesday    2014-03-18
4012NM14301    peach   18    wednesday    2014-03-18

我已经打开了第一个文件,并尝试将数据放入散列(或者如果我正确理解这些概念,则更确切地说是散列和数组的组合),以便使用 ID 作为唯一键来删除重复项。但是,它并没有覆盖具有相同 ID 的条目,而是似乎仍然添加了它,所以我仍然以重复记录结束。

我想看看这个:

ID number
4011NM16001
4011NM15687
4012NM15002
4012NM14301

但我还是看到了这个:

ID number      
4011NM16001    
4011NM16001    
4012NM15687    
4012NM15002    
4012NM14301    
4012NM14301    

是我在代码中输入了错误还是我没有正确使用哈希?我还是 Perl 的新手,所以我使用了以前程序的部分内容,并尝试边学边学..

#!/usr/bin/env perl

use DBI;

use strict;
use warnings;

my $file1  = 'location1.csv';   #file1 containing records with duplicates
my $exists = 'location3.csv';  #output file with unique IDs that will be compared to file2

open (EXISTS, ">$exists") or die "Cannot open $exists";
    print EXISTS "ID number\n";

open (FILE1, "$file1") or die "Cannot open $file1";

while (<FILE1>){

    my %file1;

    my $line = $_;
    $line =~ s/\s*$//g;

    my ($ID, $a, $b, $c, $d) = split('\,', $line);
    next if !$ID or substr($ID,0,2) eq 'ID';

    $file1{$ID}[0]=$ID;  #unique ID number
    $file1{$ID}[1]=$a;   #record a
    $file1{$ID}[2]-$b;   #record b
    $file1{$ID}[3]=$c;   #record c
    $file1{$ID}[4]=$d;   #record d

    print EXISTS "$file1{$ID}[0]\n";
}

exit;

【问题讨论】:

  • 我想你知道你不需要use DBI 吗?该模块从未使用过

标签: arrays perl hash duplicates key


【解决方案1】:

您正在为每个输入行打印该行,而不仅仅是不存在的行。 将print移到作业段落前,改为

print EXISTS "$ID\n" unless exists $file1{$ID};

【讨论】:

  • 恭喜你突破 100k :)
  • @simbabque:谢谢。还在等待“一盒很酷的东西”:-)
  • 祝海关好运。他们以太低的价格宣布我的 1000 万个问题获胜箱,比如 1 美元的 T 恤,但它通过了。我认为它还有 10 倍 0.10 美元的贴纸。
  • 如果你到时拿到了 SO T 恤,请把它带到 YAPC。
  • @choroba:这还是一件事吗?
【解决方案2】:

除了choroba's diagnosis,你还需要在while循环之外声明散列,否则循环的每次迭代都在处理一个新的空散列

这是您的代码版本,它使用最佳实践 Perl 并产生您想要的结果。请注意,我必须更改输入文件 location1.csv 的格式,因为您显示的值不包含任何逗号

#!/usr/bin/env perl

use strict;
use warnings;

my $file1  = 'location1.csv';    # file1 containing records with duplicates
my $exists = 'location3.csv';    # output file with unique IDs that will be compared to file2

open my $exists_fh, '>', $exists or die qq{Unable to open "$exists" for output: $!};
print $exists_fh "ID number\n";

open my $file1_fh, '<', $file1 or die qq{Unable to open "$file1" for input: $!};
<$file1_fh>; # skip header line

my %file1;

while ( <$file1_fh> ) {

    next unless /\S/; # Skip blank lines

    s/\s+\z//;

    my @fields = split /,/;
    my $id = $fields[0];

    next if $file1{$id}; # Skip this record if the ID is already known

    $file1{$id} = \@fields;

    print $exists_fh "$id\n"
}

输出

ID number
4011NM16001
4012NM15687
4012NM15002
4012NM14301

【讨论】:

  • 感谢您的回答!!我现在尝试在 while 循环之外声明哈希和打印(即在最后一个 } 括号之后),但它随后给出了 $file1 和 $ID 变量的“全局符号..需要显式包名称”错误,据我所知表示该变量尚未声明。我接下来尝试您的代码 - 它是否仍将所有数据添加到哈希/数组中(即所有列中的所有数据),还是仅提取 ID 列中的唯一值?
  • @DKru:你可以在while循环之后打印散列的内容,或者只是用它来确定之前是否见过这个ID,然后打印每个新的IDinside 循环,这就是我的代码所做的
  • Global symbol .. requires explicit package name 确实意味着没有声明一个变量(有一些动作可以将该消息更改为更有用的东西!)这是因为您已将您的 print 语句移到循环其中$ID 不存在。但是除非您更改了其他内容,否则$file1 应该存在于程序中的任何地方,所以我不确定发生了什么。即使你的意思是%file1,你说你已经把它的声明移到了循环之外,所以这也应该没问题。如果不查看您编写的内容,就无法进一步调试您的代码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-23
  • 2013-08-04
  • 2018-04-07
  • 1970-01-01
  • 1970-01-01
  • 2014-02-17
相关资源
最近更新 更多