对列值进行排序并搜索值

时间:2018-03-11 12:09:28

标签: perl

我的脚本的输入是这个文件,其中包含如下数据。

A food 75
B car 136
A car 69
A house 179
B food 75
C car 136
C food 85

对于第二列的每个不同值,我想打印第三列中的数字不同的任何行。

示例输出

C food 85 
A car 69 

这是我的Perl代码。

#! /usr/local/bin/perl

use strict;
use warning;

my %data = ();

open FILE, '<', 'data.txt' or die $!;
while ( <FILE> ) {
    chomp;
    $data{$1} = $2 while /\s*(\S+),(\S+)/g;
}
close FILE;

print $_, '-', $data{$_}, $/ for keys %data;

我可以打印哈希键和值,但无法获得所需的输出。

有关如何使用Perl执行此操作的任何指示?

2 个答案:

答案 0 :(得分:1)

据我所知,你需要一个列出所有行的列表,其中有一个&#34;奇怪的一行&#34;具有相同的项目类型和第三列中与其他所有

不同的数字

我认为这就是你需要的

它将所有数据读入散列%data,因此$data{$type}{$n}是使用该对象类型和数字的所有数据行的(引用)数组

然后再次扫描哈希,查找并打印所有只有一行的给定类型/数字的实例,其中有相同对象类型的其他值(否则它会是唯一的条目而不是&#34;奇怪的一个&#34;)

use strict;
use warnings 'all';
use autodie;

my %data;

open my $fh, '<', 'data.txt';

while ( <$fh> ) {
    my ( $label, $type, $n) = split;
    push @{ $data{$type}{$n} }, $_;
}

for my $type ( keys %data ) {

    my $items = $data{$type};

    next unless keys %$items > 1;

    for my $n ( keys %$items ) {
        print $items->{$n}[0] if @{ $items->{$n} } == 1;
    }
}

输出

C food 85
A car 69

请注意,如果输入类似于

,则可能会为给定的对象类型打印多行
B car 22
A car 33
B car 136
C car 136

这有两个&#34;奇怪的&#34;对于给定的对象类型只出现一次,因此将打印B car 22A car 33

答案 1 :(得分:0)

以下是指示:

首先,在输出之前,你需要记住某处的线条 其次,您需要根据您设置的规则丢弃以前记住的对象线 在您的情况下,规则是在对象的编号与先前记住的编号不同时丢弃 这两项任务都可以使用hash完成。

对于每一行:

    my ($letter, $object, $number)=split /\s+/, $line;
    if (!defined($hash{$object}) || $hash{$object}[0]!=$number) {
      $hash{$object}=[$number, $line];
    }

第三,您需要输出哈希:

for my $object(keys %hash) {
    print $hash{$object}[1];
}

但是存在一个问题:哈希是一种无序结构,它不会按照你把它们放入哈希的顺序返回它的键。
所以,第四个:您需要为哈希数据添加排序,这可以像这样完成:

  $hash{$object}=[$number,$line,$.]; # $. is the row number over all the input files or STDIN, we use it for sorting

在输出部分中,您使用存储的行号进行排序 (有关$a$b变量)的详细信息,请参阅sort

for my $object(sort { $hash{$a}[2]<=>$hash{$b}[2] } keys %hash) {
    print $hash{$object}[1];
}

关于评论

我确信我的代码不包含任何错误 如果我们在一些高级用户编辑之前查看问题,它会说:

[举]
现在,如果数字列(第三个)具有不同的值(第二列中的位置匹配)...然后仅打印不匹配的数字行。例如..
    食物75
    B车136
    一辆车69
    房子179
     B食物75
    B车136
     C食物85

示例输出(由于数字列不匹配)
     C食物85
[/ cite]

我只能将print only the mismatched number line解释为:打印数字更改的对象的最后一行。这显然符合OP提供的示例。

即便如此,在我的回答中,我通过声明根据OP想要的任何规则完成省略行来解决了误解的可能性。
在下面我说明了当时在我看来是什么规则 我认为它很好地解决了OP问题,因为毕竟, OP需要指针

现在我的回答是批评的,因为它与编辑的(很久以后而不是OP)要求不匹配。

我不同意。

关于空格:指定分割/\s+/在这里不是错误,尽管有一些评论试图断言。
虽然我同意" "对于拆分很常见,但我不同意在很多情况下必须使用" "而不是/\s+/
/\s+/是一个正则表达式,它是拆分的常规参数,而" "是速记,实际上掩盖了含义。
有了这个,我决定在我的示例中使用显式split /\s+/, $line,而不仅仅是split " ", $line或仅split 来显示perl的内部工作

我认为对任何一个新人都很重要。

使用/\s+/是完全可以的,但是如果您希望在数据中有前导空格,请务必小心,请咨询perldoc -f split并确定/\s+/是否符合您的需求。