C 基于列和排序合并两个文件

C 基于列和排序合并两个文件,c,linux,perl,awk,merge,C,Linux,Perl,Awk,Merge,我有两个文件,FILE1和FILE2,它们具有不同数量的 列和某些列是相同的。在这两个文件中,第一列是 行标识符。我想合并这两个文件(FILE1和FILE2) 不更改列的顺序,以及缺少 值输入值“5” 例如FILE1(第一列是行ID,A1是第一行,A2 第二条……): FILE1的列名为(在另一个文件中指定) 也就是说,行A1,列Affy1中的值是1 行A3列Affy5中的值为2 v~~~~~ Affy3 A1 1 2 5 1 A2 0 2 1 1 A3 1 0 2 2 ^~

我有两个文件,
FILE1
FILE2
,它们具有不同数量的 列和某些列是相同的。在这两个文件中,第一列是 行标识符。我想合并这两个文件(
FILE1
FILE2
) 不更改列的顺序,以及缺少 值输入值“5”

例如
FILE1
(第一列是行ID,
A1
是第一行,
A2
第二条……):

FILE1
的列名为(在另一个文件中指定)

也就是说,行
A1
,列
Affy1
中的值是
1
A3
Affy5
中的值为
2

     v~~~~~ Affy3
A1 1 2 5 1 
A2 0 2 1 1 
A3 1 0 2 2
   ^~~~ Affy1
类似地,对于
FILE2

B1 1 2 0
B2 0 1 1
B3 5 1 1
以及它的列名

Affy1
Affy2
Affy3
意思是

     v~~~~~ Affy2
B1 1 2 0
B2 0 1 1
B3 5 1 1
   ^~~~ Affy1
我想根据列名对列进行合并和排序,并放置一个 “5”表示缺少值。因此,合并结果如下:

A1 1 5 2 5 1
A2 0 5 2 1 1
A3 1 5 0 2 2
B1 1 2 0 5 5 
B2 0 1 1 5 5 
B3 5 1 1 5 5
以及以下栏目:

Affy1
Affy2
Affy3
Affy4
Affy5
也就是说,

     v~~~~~~~ Affy2
A1 1 5 2 5 1
A2 0 5 2 1 1
A3 1 5 0 2 2
B1 1 2 0 5 5 
B2 0 1 1 5 5 
B3 5 1 1 5 5
   ^~~~ Affy1
实际上,我在每个文件中有超过700K列和超过2K行。提前谢谢

为了好玩——嗯

#/usr/bin/perl
使用警告;
严格使用;
使用常量{A=>1,B=>2,两者都=>3};
#我不从文件中读取数据
my@columns=qw(Affy1 Affy2 Affy3 Affy4 Affy5);
my@locations=(两者,B,两者,A,A);
我的@contentA=([“A1”,1,2,5,1],
[“A2”、0、2、1、1],
[“A3”,1,0,2,2]);
my@contentB=([“B1”,1,2,0],
[“B2”,0,1,1],
[“B3”、5、1、1]);
#我假设两个文件的行数相同
我的@ares=();
我的@bres=();
对于(我的$i=0;$i<@contentA;++$i){
#这将使用大量内存和大量数据
#也许你在两个临时结果文件中写下它,然后对它们进行分类
#最后一起
#另一种选择是先迭代
#文件A,然后在文件A上
我的@row_a=();
我的@row_b=();
推送@row_a,shift@{$contentA[$i]};#id
推送@row_b,shift@{$contentB[$i]};#id
foreach my$loc(@位置){
如果(A=$loc){
按@row_a,shift{$contentA[$i]};
在第二排第5排推动;
}
如果(B=$loc){
按a排5的按钮;
按@row_b,shift{$contentB[$i]};
}
如果(两者==$loc){
按@row_a,shift{$contentA[$i]};
按@row_b,shift{$contentB[$i]};
}
}
按@ares,\@row\u a;
按@bres,\@row\U b;
}
foreach我的$ar(@ares){
打印联接“”@{$ar};
打印“\n”;
}
foreach my$br(@bres){
打印联接“”@{$br};
打印“\n”;
}
打印联接(“\n”,@列);
打印“\n”;

困难的部分是,当某些标题仅出现在一个文件中时,对标题进行排序。我知道的最好的方法是使用模块构建一个有向图,并对元素进行拓扑排序

完成后,只需将每个文件中的值分配到正确的列,并在空白处填入5s即可

我已经将标题合并为每个数据文件的第一行,所以这个程序处理这些数据

file1.txt
ID Affy1 Affy3 Affy4 Affy5
A1 1 2 5 1
A2 0 2 1 1
A3 102
file2.txt
ID Affy1 Affy2 Affy3
B1 1 2 0
B2 0 1 1
B3 5 1
这是代码

合并columns.pl
使用严格;
使用“全部”警告;
使用Graph::Directed;
my@files=qw/file1.txt file2.txt/;
#创建一个包含两个文件句柄的数组
#
我的@fh=地图{
打开我的$fh,'新;
对于我的$f(0,1){
my$file_heads=$file_heads[$f];
$g->0..$\$file\u heads-1的添加边($file\u heads->[$\u],$file\u heads->[$\u+1]);
}
$g->Topology_排序;
};
#形成一个哈希表,将标题名转换为列索引以进行输出
#
我的%ordered_headers=映射{$ordered_headers[$\u]=>$\u0$#有序_头;
#打印每个文件的标题和修改后的记录。使用散列来
#将标题名称转换为列索引
#
打印“@ordered_headers\n”;
对于我的$i(0..$#fh){
my$fh=$fh[$i];
my@file_heads=@{$file_heads[$i]};
my@splice=map{$ordered_headers{$}}@file_heads;
而(){
下一个除非/\S/;
我的@columns;
@列[@splice]=拆分;
@columns[0..$#ordered_headers]的$_/=5;
打印“@columns\n”;
}
}
输出
ID Affy1 Affy2 Affy3 Affy4 Affy5
A1 1 5 2 5 1
A2 0 5 2 1 1
A3 150 2
B1 1 2 0 5 5
B2 01 15
B351155

到目前为止,您尝试了什么?StackOverflow不是一个让别人为你写代码的网站。我对编程和学习过程都是新手。我使用过Linux、Perl和C。我知道如何合并文件,但我的问题是同时根据列名以及我拥有的大量行和列来合并和排序它们。好的,那么在您的示例中,实际文件的A1部分是吗?或者它只是为了我们可以引用第一行?它只是对每一行的引用,存在于我的实际文件中。我不理解“合并”的概念,但我得到了“追加”,因为
a
集似乎与
B
集无关。我可以看到您正在用
5
填充缺少的列,但我不明白为什么第三个输出行是
A3 1 5 0 0
而不是
A3 1 5 0 2 2
。谢谢!当我尝试运行它时,第3行出现了一个错误。另外,最后三行(B1、B2、B3)的输出不正确。@Sarah:请问有什么错误?你运行的是什么版本的Perl?@Sarah:我猜你有一个非常旧的Perl版本,它不支持
autodie
,所以我删除了它,并用一个变通方法替换了它。我很抱歉--我使用了A文件头的名称来重新排列B记录;这个bug现在已经修复了,问题是perl版本。我修好了,它工作了:)非常感谢!代码与示例完全一致,但是如何读取文件而不是输入数据?事实上我有
Affy1
Affy2
Affy3
Affy4
Affy5
     v~~~~~~~ Affy2
A1 1 5 2 5 1
A2 0 5 2 1 1
A3 1 5 0 2 2
B1 1 2 0 5 5 
B2 0 1 1 5 5 
B3 5 1 1 5 5
   ^~~~ Affy1
#!/usr/bin/perl

use warnings;
use strict;
use constant {A => 1, B => 2, BOTH =>3};

# I don't read data from file
my @columns = qw(Affy1 Affy2 Affy3 Affy4 Affy5);
my @locations = (BOTH, B,    BOTH, A,    A);

my @contentA = (["A1", 1, 2, 5, 1],
                ["A2", 0, 2, 1, 1],
                ["A3", 1, 0, 2, 2]);
my @contentB = (["B1", 1, 2, 0],
                ["B2", 0, 1, 1],
                ["B3", 5, 1, 1]);

#I assume both files have the same amount of lines

my @ares  = ();
my @bres = ();
for(my $i = 0; $i < @contentA; ++$i){
  # this uses a lot of memory whith huge amounts of data
  # maybe you write this in two temp result files and cat them
  # together at the end
  # another alternative would be to iterate first over
  # file A and then over file A
  my @row_a = ();
  my @row_b = ();
  push @row_a, shift @{$contentA[$i]}; #id
  push @row_b, shift @{$contentB[$i]}; #id
  foreach my $loc (@locations){
    if(A == $loc){
      push @row_a, shift @{$contentA[$i]};
      push @row_b, 5;
    }
    if(B == $loc){
      push @row_a, 5;
      push @row_b, shift @{$contentB[$i]};
    }
    if(BOTH == $loc){
      push @row_a, shift @{$contentA[$i]};
      push @row_b, shift @{$contentB[$i]};
    }
  }
  push @ares, \@row_a;
  push @bres, \@row_b;
}

foreach my $ar(@ares){
  print join " ", @{$ar};
  print "\n";
}

foreach my $br(@bres){
  print join " ", @{$br};
  print "\n";
}

print join("\n", @columns);
print "\n";