Text-Processing

文本操作 - 根據值將列轉置為行

  • August 28, 2019

我想編寫一個程式碼來操作我的 CSV 文件中的文本,該文件包含以下內容:

71w - Rus,51200
71w - Phi,307200
71w - Ukr,307200
71w - Ukr,51200
71w - Mic,102400
71w - Mic,51200
71w - Jul,256000
71w - Jul,51200
71w - Pro,256000
71w - Uni,51200
71w - Ind,50176
71w - Ind,40960
71w - Sin,358400
71w - May,20480
71w - Tha,512000
71w - Tha,972800
71w - Bar,1280000
71w - Bar,102400
71w - Bar,2048000
71w - Upg,358400
71w - Leg,20480
71w - Res,153600

我想收集具有相同值的列並將其放在相應的行上,如下所示:

71w - Rus,51200
71w - Phi,307200
71w - Ukr,307200,51200
71w - Mic,102400,51200
71w - Jul,256000,51200
71w - Pro,256000
71w - Uni,51200
71w - Ind,50176,40960
71w - Sin,358400
71w - May,20480
71w - Tha,512000,972800
71w - Bar,1280000,102400,2048000
71w - Upg,358400
71w - Leg,20480
71w - Res,153600

謝謝你。

一個很好的方法是使用關聯數組或雜湊。每個雜湊的鍵是第一個欄位(我將它們稱為“ids”,因為需要更好的術語),並且為每個鍵儲存的值將是一個字元串,其中包含一個逗號分隔的值列表id,或包含相同的數組。

awk:

這個 awk 版本使用逗號分隔的字元串,因為(在 awk 中)它比處理包含數組的關聯數組更容易。

#!/usr/bin/awk -f

BEGIN {
 FS=" *, *";
 OFS="";
}

{
 key=$1; $1=""; $0=$0;

 if (length(ids[key]) > 0) {
   ids[key]=ids[key]","$0;
  } else {
   ids[key] = $0
  };
}

END {
 for (k in ids) {
   print k "," ids[k]
 }
}

在 perl 中,處理數組雜湊(或“HoA”)並不比處理串聯字元串更難(而且更有用/更靈活):

#!/usr/bin/perl -w

use strict;

my %ids = ();

while(<>) {
 chomp;
 my @F = split /\s*,\s*/;
 push @{ $ids{$F[0]} }, $F[1];
};


END {
 foreach my $key (keys %ids) {
   print $key . ',' .  join(",",@{ $ids{$key} }), "\n";
 }
}

awk 和 perl 版本的輸出是相同的:

71w - Ukr,307200,51200
71w - Bar,1280000,102400,2048000
71w - Res,153600
71w - Upg,358400
71w - Sin,358400
71w - Mic,102400,51200
71w - May,20480
71w - Tha,512000,972800
71w - Jul,256000,51200
71w - Uni,51200
71w - Ind,50176,40960
71w - Pro,256000
71w - Rus,51200
71w - Leg,20480
71w - Phi,307200

注意:awk 和 perl 版本的輸出沒有任何特定的順序,每次執行時可能會以不同的順序出現。這是因為 awk “關聯數組”和 perl “雜湊”(同一事物的兩個名稱)本質上是無序的。

如果需要,您可以將輸出通過管道傳輸到sort。或者,在 perl 中,您可以使用:

     foreach my $key (sort keys %ids) {

代替:

     foreach my $key (keys %ids) {

另外 - 因為我們將每個 id 的單獨值儲存在一個數組中,所以在 perl 中也很容易對這些值進行排序。例如,將 perl 版本中的整個END塊替換為:

END {
 foreach my $key (sort keys %ids) {
   print $key . ',' .  join(",",sort @{ $ids{$key} }), "\n";
 }
}

輸出將是:

71w - Bar,102400,1280000,2048000
71w - Ind,40960,50176
71w - Jul,256000,51200
71w - Leg,20480
71w - May,20480
71w - Mic,102400,51200
71w - Phi,307200
71w - Pro,256000
71w - Res,153600
71w - Rus,51200
71w - Sin,358400
71w - Tha,512000,972800
71w - Ukr,307200,51200
71w - Uni,51200
71w - Upg,358400

引用自:https://unix.stackexchange.com/questions/537799