当前位置: 首页 > 知识库问答 >
问题:

Perl多维数组列比较显示满足条件的全部内容

白君之
2023-03-14

在获取数组索引进行比较和显示结果时,我遇到了一些小问题。我有一个以制表符分隔的文件,有9列和100多行。我想比较第I行的第8列元素和第I行的第7列元素。如果小于第7列元素,则打印整行;如果大于第7列元素,则比较两行的第6个元素;如果第6个元素较大,则仅打印该行。

样本文件

Recep_L_domain  PF01030.22      112     sp|P00533|EGFR_HUMAN    2.50E-30        104.7   57      167     Receptor
Furin-like      PF00757.18      149     sp|P00533|EGFR_HUMAN    4.10E-29        101.3   185     338     Furin-like
Recep_L_domain  PF01030.22      112     sp|P00533|EGFR_HUMAN    3.60E-28        97.8    361     480     Receptor
GF_recep_IV     PF14843.4       132     sp|P00533|EGFR_HUMAN    1.60E-46        157.2   505     636     Growth
Pkinase PF00069.23      264     sp|P00533|EGFR_HUMAN    2.70E-39        135     712     964     Protein
Pkinase_Tyr     PF07714.15      260     sp|P00533|EGFR_HUMAN    8.40E-88        293.9   714     965     Protein

例如,如果我们比较最后两行,那么第8列元素比下一行的第7列元素大,那么在这种情况下,它应该比较两个第6列元素,并打印唯一较大的行。所以从这两行开始,它应该只打印最后一行。对我来说,下面的代码只打印较小的值,但是我想问一下,如果第8列较大,我如何比较第6列元素和打印结果?

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

open(IN,"<samplecode.txt");

my @Alifrom;
my @Alito;
my @data; ## multidimensional array

while(<IN>){
    chomp $_;
    #next if $_=undef;
    my @line = split("\t", $_);
    ##my($a, $b, $c, $d, $e, $f, $g, $h, $i) = split(/\t/,$_); // catch data and storing into multiple scalar variable

    push @data, [@line];
}

for (my $i = 0; $i < @data ; $i++){

    if ($data[$i][7] gt $data[$i][6]){

        for (my $j = 0; $j < @{$data[$i]}; $j++){
            #@Alifrom = map $data[$i][$j+6], @data;
            print "$data[$i][$j]\t";
        }
    }
    #else
    print "\n";
}

共有1个答案

潘弘博
2023-03-14

你问题中的描述并不完全清楚,但我是在做一个有根据的猜测。

首先,不应该将整个文件读入数组。如果你的文件只有100行,这不是问题,但如果有更多的行,这将消耗大量内存。

你说你想比较每一行i中的值和第一行i中的值,所以基本上在每一行中,你都想看下一行的值。这意味着你需要一次在内存中最多保留两行。因为这是线性的,你可以读取第一行,然后读取第二行,进行比较,完成后,将第二行作为新的第一行。

在循环中,您总是读取第二行,并在之前的迭代中将第一行作为第二行读取时,将其保留在第一行附近。

为此,将读取和拆分转换为一个函数是有意义的。您可以传递一个文件句柄。在我上面的例子中,我在__DATA__部分中使用了DATA,但是您可以只打开我的$fh

因为在某些情况下,您希望打印整行,所以不应仅以破坏性的方式chompsplit打印整行,而应保留实际的整行,包括换行符。因此,我们让函数读取并拆分返回两个值:作为标量字符串的整行,以及已清理列的数组引用。

如果没有更多的行可读,我们将返回一个隐式的unde,这将使循环停止时运行。因此,您永远无法处理文件的最后一行。

比较时,请注意Perl中的列表索引总是从零开始,因此第7列是索引[6]

下面是一个示例实现。

use strict;
use warnings;

# this function reads a line from the filehandle that's passed in and returns
# the row as a string and an array ref of all columns, or undef if there are
# no more lines to read
sub read_and_split {
    my $fh = shift;

    # read one line and return undef if there is no more data
    my $row = <$fh>;
    return unless defined $row;

    # split into columns
    my @cols = split /\s+/, $row;    # Stack Overflow does not like tabs, use \t

    # only chomp after splitting so we retain the original line for printing
    chomp $cols[-1];

    # return both things
    return $row, \@cols;
}

# read the first line
my ( $row_i, $cols_i ) = read_and_split( \*DATA );

# read subsequent lines
while ( my ( $row_i_plus_one, $cols_i_plus_one ) = read_and_split( \*DATA ) ) {

    # 7th col of i is smaller than 6th col of i+1
    if ( $cols_i->[7] < $cols_i_plus_one->[6] ) {
        print $row_i;
    }
    else {
        # compare the 6th element of both row and only print
        # if the row if the 6th element is bigger
        if ( $cols_i->[5] > $cols_i_plus_one->[5] ) {
            print $row_i;
        }
    }

    # turn the current i+1 into i for the next iteration
    $row_i  = $row_i_plus_one;
    $cols_i = $cols_i_plus_one;
}

__DATA__
Recep_L_domain  PF01030.22      112     sp|P00533|EGFR_HUMAN    2.50E-30        104.7   57      167     Receptor
Furin-like      PF00757.18      149     sp|P00533|EGFR_HUMAN    4.10E-29        101.3   185     338     Furin-like
Recep_L_domain  PF01030.22      112     sp|P00533|EGFR_HUMAN    3.60E-28        97.8    361     480     Receptor
GF_recep_IV     PF14843.4       132     sp|P00533|EGFR_HUMAN    1.60E-46        157.2   505     636     Growth
Pkinase PF00069.23      264     sp|P00533|EGFR_HUMAN    2.70E-39        135     712     964     Protein
Pkinase_Tyr     PF07714.15      260     sp|P00533|EGFR_HUMAN    8.40E-88        293.9   714     965     Protein

它输出以下行:

Recep_L_domain  PF01030.22      112     sp|P00533|EGFR_HUMAN    2.50E-30        104.7   57      167     Receptor
Furin-like      PF00757.18      149     sp|P00533|EGFR_HUMAN    4.10E-29        101.3   185     338     Furin-like
Recep_L_domain  PF01030.22      112     sp|P00533|EGFR_HUMAN    3.60E-28        97.8    361     480     Receptor
GF_recep_IV     PF14843.4       132     sp|P00533|EGFR_HUMAN    1.60E-46        157.2   505     636     Growth

请注意,关于比较第六列的部分在您的问题中不是很清楚。我假设我们比较第六列和第I行,如果匹配的话。如果我们打印第一行,我们可能会打印两次。

 类似资料:
  • 问题内容: 如何比较php中的多维数组?有没有简单的方法? 问题答案: 我知道的最简单的方法是: 请注意,您也可以使用。它们之间的区别是: 使用 Double equals时 ,顺序很重要: 对于 Triple equals ,类型很重要:

  • 因此,我正在编写一个数独解算器,使用9x9数组作为网格,使用9x9x9数组作为其可能性。由于我使用的回溯算法,我必须检查数独是否仍然有效,又名: 如果有一个字段不包含数字,并且没有剩余的可能性,则返回False。到目前为止,我实现了以下几点: 例如,如果(j,i)处的正方形包含选项2、3和7,则相应的可能性数组为: 我试图在求解器中避免这样的循环。我尝试如下: 这返回了一个nx9数组,其中n是我的

  • 问题内容: 当我在大学时使用C ++时,我被告知要尽可能使用多维数组(因此称为MDA),因为它以较大的块分配,因此具有更好的内存局部性。另一方面,阵列数组(AoA)被分配为多个较小的块,可能分散在物理内存中发现空缺的所有位置。 所以我想第一个问题是:这是神话,还是值得遵循的建议? 假设是后者,那么下一个问题将是在没有真正MDA的Java之类的语言中做什么。当然,用1DA模拟MDA并不难。本质上,具

  • 问题内容: 使用以下模型: 如果我要查找包含至少一篇文章的订单操作,则可以按预期工作: 但是,如果要查找订单中所有商品的订单操作,正确的方法是什么? 引发错误(我理解为什么会这样)。 问题答案: 一个简单的解决方案: 这只是一个查询,但每篇文章都有一个内部联接。对于多篇文章,Willem更巧妙的解决方案应该会表现更好。

  • 这是我的数据库的简化版本。 我正在尝试选择2016年B列中的值为零的所有商店。所以在这种情况下,我希望选择商店A和C。 仅选择 B = 0 的各个行。而我想要的是选择这个 提前感谢帮助或建议。

  • 问题内容: 我想要一种改进我的sql代码的好方法,当条件满足时,我必须使用内部联接。我目前正在复制代码: 我想以这种方式做到这一点: 编辑: 解决方案(由于@Damien_The_Unbeliever): 问题答案: 这应该(大约)执行相同的操作: 当然,这还意味着必须编写对其中的列的任何其他引用,以期望此类列为。