[英]Compare two CSV Files with Perl
我有兩個CSV文件,我想與Perl進行比較。
我有使用Text::CSV::Slurp
將文件導入Perl的代碼,它為我提供了一個很好的文件散列引用數組。
使用Data::Dumper::Concise
正確顯示我的所有數據導入。
use strict;
use warnings;
use Text::CSV::Slurp;
use Data::Dumper::Concise;
my $file1_src = "IPB-CSV.csv";
my $file2_src = "SRM-CSV.csv";
my $IPB = Text::CSV::Slurp->load(file => $file1_src);
my $SRM = Text::CSV::Slurp->load(file => $file2_src);
print Dumper($IPB);
print Dumper($SRM);
轉儲的結果看起來像這樣
$ IPB
[
{
Drawing => "1001"
},
{
Drawing => "1002"
},
{
Drawing => "1003"
}
]
$ SRM
[
{
Drawing => "1001",
Figure => "Figure 2-8",
Index => 2,
Nomenclature => "Some Part"
},
{
Drawing => "1002",
Figure => "Figure 2-8",
Index => 2,
Nomenclature => "Some Part"
},
{
Drawing => "2001",
Figure => "Figure 2-8",
Index => 2,
Nomenclature => "Some Part"
},
{
Drawing => "2002",
Figure => "Figure 2-8",
Index => 2,
Nomenclature => "Some Part"
}
]
我想根據每個哈希的Drawing
鍵比較兩個數組,並創建兩個CSV文件,如下所示
一個包含$IPB
但不是$SRM
,僅包含`Drawing列中的數據。
另一個項目在$SRM
但不在$IPB
,包含與Drawing
列相關的所有字段。
我找到了很多信息來比較文件以查看它們是否匹配,或者比較單個數據片段的哈希值或數組,但我找不到特定於我需要的東西。
由於繪圖是一種排序標准,為什么不將數據“索引”到一個更方便的地方,其中繪圖索引是關鍵,相應的數據是相應的值?
my %ipb;
for my $record ( @$IPB ) {
my $index = $record->{Drawing};
push @{ $ipb{$index} }, $record;
}
my %srm;
for my $record ( @$SRM ) {
my $index = $record->{Drawing};
push @{ $srm{$index} }, $record;
}
現在找出$IPB
和$SRM
獨有的索引應該是輕而易舉的:
use List::MoreUtils 'uniq';
my @unique_ipb = uniq( grep { $ipb{$_} and not $srm{$_} } keys( %ipb ), keys( %srm ) );
my @unique_srm = uniq( grep { $srm{$_} and not $ipb{$_} } keys( %ipb ), keys( %srm ) );
兩者有什么共同之處?
my @intersect = uniq( grep { $srm{$_} and $ipb{$_} } keys( %ipb ), keys( %srm ) );
繪圖索引1002的所有圖號是什么?
print $_->{Figure}, "\n" for @{ $ipb{1002} // [] }, @{ $srm{1002} // [] };
這個簡短的程序使用$ipb
和$srm
示例值,並創建我認為你想要的輸出。 (除了包名等全局標識符外, 請不要使用大寫字母。)
有幾個問題
使用Text::CSV::Slurp
會為您留下兩個散列數組,這些散列對此任務沒有用,無需進一步索引。 通過逐行處理文件,從頭開始創建適當的數據結構會更好
你說你的第二個文件必須包含與每個Drawing
鍵相關的所有信息,但是,因為Perl哈希本質上是無序的,所以Text::CSV::Slurp
已經丟失了字段名稱的順序。 可以做的最好的事情是按照找到的順序打印數據,但是在顯示字段名稱的標題行之前。 這是避免Text::CSV::Slurp
另一個原因
use strict;
use warnings;
use autodie;
# The original data
my $ipb = [{ Drawing => 1001 }, { Drawing => 1002 }, { Drawing => 1003 }];
my $srm = [
{
Drawing => "1001",
Figure => "Figure 2-8",
Index => 2,
Nomenclature => "Some Part"
},
{
Drawing => "1002",
Figure => "Figure 2-8",
Index => 2,
Nomenclature => "Some Part"
},
{
Drawing => "2001",
Figure => "Figure 2-8",
Index => 2,
Nomenclature => "Some Part"
},
{
Drawing => "2002",
Figure => "Figure 2-8",
Index => 2,
Nomenclature => "Some Part"
}
];
# Index the data
my %srm;
for my $item (@$srm) {
my $drawing = $item->{Drawing};
$srm{$drawing} = $item;
}
my %ipb;
for my $item (@$ipb) {
my $drawing = $item->{Drawing};
$ipb{$drawing} = 1;
}
# Create the output files
open my $csv1, '>', 'file1.csv';
for my $id (sort keys %ipb) {
next if $srm{$id};
print $csv1 $id, "\n";
}
close $csv1;
open my $csv2, '>', 'file2.csv';
my @keys = keys %{ $srm->[0] };
print $csv2 join(',', @keys), "\n";
for my $id (sort keys %srm) {
next if $ipb{$id};
print $csv2 join(',', @{$srm{$id}}{@keys}), "\n";
}
close $csv2;
產量
file1.csv
1003
file2.csv
Drawing,Nomenclature,Index,Figure
2001,Some Part,2,Figure 2-8
2002,Some Part,2,Figure 2-8
這有點復雜,因為您的數據結構不太適合比較。 您有對散列引用數組的引用,並且您關心hashref的其中一個鍵中的數據。 我的第一步是將IPB壓平為一個數組(因為此下沒有數據),並將SRM轉換為單個hashref。
my @ipbarray = map { ${$_}{Drawing} } $IPB; # Creates an array from IPB.
my $srmhash = {};
for my $hash ($SRM) {
${$srmhash}{${$hash}{Drawing}} = $hash unless defined ${$srmhash}{${$hash}{Drawing}}; # Don't overwrite if it exists
}
現在我們有2個可行的數據結構。
下一步是對比這些值:
my @ipbonly = ();
my @srmonly = ();
for my $ipbitem (@ipbarray) {
push @ipbonly, ( Drawing => $ipbitem } unless defined ${$srmhash}{$ipbtem};
}
for my $srmitem (keys $srmhash) {
push @srmonly, ${$srmhash}{$srmitem} unless grep { $_ == $srmitem } @ipbarray;
}
此時,@ ipbonly和@srmonly將包含您想要的數據。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.