【问题标题】:Compare two texts numerically用数字比较两个文本
【发布时间】:2013-12-09 01:40:28
【问题描述】:

我有这两个文件,我想用数字比较它的内容。

文本1:

C_A C_A 0.0000 0.0000 0 0 50 47 100 390
C_A/I0/I0 INV 0.0200 0.2210 0 0 20 200 30 100
C_A/I0/I2 INV 1.0400 0.2210 0 0 530 200 250 261

文本2:

C_A C_A 0.0000 0 0 0 50 47 100 390
C_A/I0/I0 INV 0.0200 0.2213 0 0 20 200 30 100
C_A/I0/I2 INV 1.04 0.2210 0 0 530 200.00 250 261

期望的输出:

C_A/I0/I0 INV has mismatch property.

到目前为止我已经尝试过了,但我收到了use of uninitialized value 的错误。请给我建议。提前感谢您的帮助。

编辑代码:

use strict;
use warnings;
my %ref_data;

open my $fh, '<', 'Text1' or die $!;
while (<$fh>) {
    chomp;
    my ($occurname, $tempname, @data) = split;
    $ref_data{$occurname} = \@data;
    }

open $fh, '<', 'Text2' or die $!;
while (<$fh>) {
    chomp;
    my ($occurname, $tempname, @data1) = split;
    my $data = $ref_data{$occurname};
    print "$occurname $tempname has mismatch property\n" if 
        grep { $data1[$_] != $data->[$_] } 0 .. $#data1;
      }
    } 

【问题讨论】:

  • != 是数字不等式运算符。你想要 ne 字符串。如果要进行数字比较,则需要将数字用作数字,而不是字符串。
  • 嗨,是的,我需要做一个数字比较,你能建议如何将数字用作数字吗?我不确定如何。
  • 不要将数据存储为字符串"@data",将其存储为数组\@data。然后在循环中比较数组,例如if (grep { $array[$_] == $array1[$_] } 0 .. $array)
  • 我已根据您的建议更正了代码。但我仍然有上面更新的错误。
  • @woolstar 我认为split 已经这样做了。

标签: arrays perl comparison numerical


【解决方案1】:

也许以下内容会有所帮助:

use strict;
use warnings;

my $file2 = pop;
my %ref_data;

while (<>) {
    my ( $occurname, $tempname, @data1 ) = split;
    $ref_data{$occurname} = \@data1;
}

push @ARGV, $file2;

while (<>) {
    my ( $occurname, $tempname, @data2 ) = split;
    my $data1 = $ref_data{$occurname};

    for ( 0 .. $#data2 ) {
        if ( $data1->[$_] != $data2[$_] ) {
            print "$occurname $tempname has mismatch property\n";
            last;
        }
    }
}

用法:&gt;perl script.pl Text1 Text2 [&gt;outFile]

最后一个可选参数将输出定向到文件。

数据集的输出:

C_A/I0/I0 INV has mismatch property

这让 Perl 处理文件 i/o。此外,for 循环用于比较数组内容——而不是grep——因为如果发现不匹配,它可以快速终止。

【讨论】:

  • 谢谢!感谢您的详细回复。刚好。另外,我一定会在你的方法中实现用法。
【解决方案2】:

smartmatch operator 怎么样?

while (<$fh>) {
    my ($occurname, $tempname, @data1) = split;
    my $data = $ref_data{$occurname};
    print "$occurname $tempname has mismatch property\n" unless @$data ~~ @data1;
}

如果你的 Perl 不够新(

编辑:添加了对匹配数组长度的检查,以在数组大小不同时抑制未初始化值警告。

if (@data1 != @$data || grep { $data1[$_] != $data->[$_] } 0 .. $#data1) {
    print "$occurname $tempname has mismatch property\n";
}

grep

还有section on arrays here for $#array

【讨论】:

  • 感谢您的回复。我的 perl 不够新,所以我使用了第二个选项,出现 use of uninitialized value in numeric ne (!=) 错误。
  • 非常感谢!!有用。我可以知道grep { $data1[$_] != $data-&gt;[$_] } 0 .. $#data1; 是如何工作的吗?
  • 它以数字方式比较数组的每个成员。 grep 返回标量上下文中真正匹配的数量。我将在帖子中添加几个链接。
  • 我明白了。非常感谢您的提示和建议。
【解决方案3】:

您可以以整数模式打包它们,然后比较打包后的值..

  unpack('s', $val1) != unpack('s', $val2);

perldoc 的注释:但不要指望奇迹:如果打包的值超过分配的字节容量,高位会被默默地丢弃,并且 unpack 肯定无法将它们从魔术帽中拉出来。而且,当您使用 s 之类的签名模板代码进行打包时,超出的值可能会导致符号位被设置,并且解包会巧妙地返回一个负值。

【讨论】:

    【解决方案4】:

    根据您需要的精确度,我只需将两者相减并测试它是否非常接近于零:

    if ( grep { my $delt= $data[$_] - $data1[$_] ;  return ( $delt < -1e-16 ) || ( $delt > 1e-16 ) ; } 1..$#data
    

    请注意,我将范围从 0..$data 更改为 1..$#data。您不需要比较第一个字段,因为它的文本。

    【讨论】:

      猜你喜欢
      • 2011-10-17
      • 1970-01-01
      • 1970-01-01
      • 2015-12-05
      • 1970-01-01
      • 2011-08-25
      • 1970-01-01
      • 1970-01-01
      • 2012-04-04
      相关资源
      最近更新 更多