0

我有两个文件,其中一个只是一个列向量,例如:

1x23
1y21
1z21
1z25

和其他是形式的矩阵

1x23 1x24 1y21 1y22 1y25 1z22 class
2000 3000 4000 5000 6000 7000 Yes
1500 1200 1100 1510 1410 1117 No

首先,我想查找第一个文件中的哪些行与第二个文件中的第一行匹配。其次,我想复制与第一个文件中的列匹配的第二个文件的列,并将它们附加到第二个文件中。因此,由于 1x23、1y21 匹配,我想在第二个中复制这两列并将其附加到类变量之前。

我希望我的结果是

1x23 1x24 1y21 1y22 1y25 1z22 1x23 1y21 class
2000 3000 4000 5000 6000 7000 2000 4000 Yes
1500 1200 1100 1510 1410 1117 1500 1100 No

我使用 perl 使用 for 循环 3 对其进行编码,但由于数据非常大,它崩溃了。我认为应该有有效的方法来做到这一点。

4

5 回答 5

3

这是另一种选择:

use strict;
use warnings;

my ( $matrix, @cols ) = pop;
my %headings = map { chomp; $_ => 1 } <>;

push @ARGV, $matrix;
while (<>) {
    my @array = split;
    @cols = grep $headings{ $array[$_] }, 0 .. $#array if $. == 1;
    splice @array, -1, 0, @array[@cols];
    print "@array\n";
}

用法:perl script.pl vectorFile matrixFile [>outFile]

数据集上的输出:

1x23 1x24 1y21 1y22 1y25 1z22 1x23 1y21 class
2000 3000 4000 5000 6000 7000 2000 4000 Yes
1500 1200 1100 1510 1410 1117 1500 1100 No

使用矢量文件中的条目创建散列。可以在矩阵文件的第一行找到的所有整数的列位置保存在@col. 矩阵行的匹配列条目split将插入到矩阵行的最后一个元素之前split。最后,编辑新行print

希望这可以帮助!

于 2013-11-14T22:27:14.223 回答
2

试试这个单行:

awk 'NR==FNR{a[$0]=1;next}FNR==1{for(i=1;i<=NF;i++)if(a[$i])k[i]}{for(x in k)$NF= sprintf("%s ",$x) $NF}7' f1 f2 

更好的可读版本:

awk 'NR==FNR{a[$0]=1;next}
     FNR==1{for(i=1;i<=NF;i++) if(a[$i])k[i]}
     {for(x in k)
          $NF= sprintf("%s ",$x) $NF}7' f1 f2

输出:

1x23 1x24 1y21 1y22 1y25 1z22 1y21 1x23 class
2000 3000 4000 5000 6000 7000 4000 2000 Yes
1500 1200 1100 1510 1410 1117 1100 1500 No
于 2013-11-14T21:23:02.010 回答
1

这是一个冗长但恕我直言的明确方法。

use strict;
use warnings;

open(my $data, '<', 'data.txt');

# read first row from the data file
my $line = <$data>;
chomp $line;

# create a list of columns
my @cols = split / /, $line;

# create hash with column indexes
my %colindex;
my $i = 0;
foreach my $colname (@cols) {
        $colindex{$colname} = $i++;
}

# Save last column ('class')
my $lastcol = pop @cols;

# get input (column names)
open(my $input, '<', 'input.txt');
my @colnames = <$input>;
close $input;

# append column names to array if there is a match
foreach (@colnames) {
        chomp;
        if (exists $colindex{$_}) {
                push @cols, $_;
        }
}

# Restore the last column
push @cols, $lastcol;

# Now process your data
open(my $out, '>', 'output.txt');

# write the header column
print $out join(" ", @cols), "\n";

while ($line = <$data>) {
        chomp $line;
        my @l = split / /, $line;
        foreach my $colname (@cols) {
                print $out $l[$colindex{$colname}], " ";
        }
        print $out "\n";
}

close $out;
close $data;
于 2013-11-14T20:23:35.230 回答
0

不知道为什么你的 Perl 代码会崩溃。我建议在常量内存中运行以下算法(在 Perl 中实现时可能比在 AWK 中更易读):

  • 读取第一个文件并构建列名列表
  • 读取数据文件的第一行(带有实际标题)
  • 将两个列表相交以生成列索引列表
  • 读取数据文件的一行并按列拆分
  • 通过使用您在步骤 3 中构建的“必需”列索引列表对其进行索引来创建一个新的列值数组。输出它。
  • 重复最后 2 个步骤。
于 2013-11-14T19:52:38.820 回答
0

你可以试试

awk -f app.awk file1.txt file2.txt

file1.txt你的第一个文件在哪里,file2.txt第二个文件在哪里,app.awk

NR==FNR {
    key[$0]++
    next
}
{
    for (i=1; i<=NF; i++)
        C[FNR,i]=$i
}

END {
    for (i=1; i<=NF; i++) 
        if (C[1,i] in key) 
            k[++j]=i                
    nc=j
    for (j=1; j<=FNR; j++) {
        for (i=1; i<NF; i++) 
           printf "%s%s",C[j,i],OFS     
        for (i=1; i<=nc; i++) 
           printf "%s%s",C[j,k[i]],OFS      
        printf "%s%s",C[j,NF],RS
    }
}
于 2013-11-14T20:15:00.097 回答