最初の列に基づいてグループ化

最初の列に基づいてグループ化

次のパターンのファイルがあります

a 12
a 13
a 15
a 14
b 5
b 6
c 2
c 5

以下のように、最初の列に基づいてグループ化したいと思います。

a 12 13 15 14
b 5 6
c 2 5

提案してください

答え1

データが(質問のように)最初の列に基づいてソートされたと仮定し、GNUを使用してスペースで区切られた最初の列に基づいてdatamashグループ化し、2番目の列を縮小します。

$ datamash -W groupby 1 collapse 2 <file
a       12,13,15,14
b       5,6
c       2,5

目的の出力を取得するには、結果の最初の列の後のタブとコンマを空白に置き換えます。

$ datamash -W groupby 1 collapse 2 <file | tr '\t,' '  '
a 12 13 15 14
b 5 6
c 2 5

入力が最初の列でソートされていない場合、sortデータは最初に渡されるか()オプションdatamashと一緒に使用されます。-s--sort


また、使用することができますミラー( mlr)そしてそのnest仕事。この関数を使用すると、2 番目の列の値を、最初の列の各固有値をスペースで区切られたリストに「埋め込む」ことができます。

$ mlr --nidx nest --implode --values --across-records --nested-fs space -f 2 file
a 12 13 15 14
b 5 6
c 2 5

または、--ivarMillerバージョン5.5.0以降で略語を使用してください(6.0.0を除く)。壊れた):

$ mlr --nidx nest --ivar space -f 2 file
a 12 13 15 14
b 5 6
c 2 5

データを事前にソートする必要はありません。

答え2

使用awk(入力ファイルが最初の列に基づいてソートされている場合):

awk '{ printf "%s", (NR==1 || pre!=$1? (NR>1? ORS:"")$1: "") OFS $2; pre=$1 }
END  { print "" }' infile

awk+を使用しますsort(入力ファイルが最初の列にソートされていない場合)。

<infile sort|
    awk '{ printf "%s", (NR==1 || pre!=$1? (NR>1? ORS:"")$1: "") OFS $2; pre=$1 }
    END  { print "" }'

またはawk、ソートされた入力またはソートされていない入力を使用してください。

awk '{ grp[$1]= (grp[$1]==""?"":grp[$1] OFS) $2 }
END  { for(x in grp) print x, grp[x] }' infile

答え3

使用幸せ(以前のPerl_6)

raku -e 'lines.map(*.words).map(*.hash).classify( *.keys, :as{$_.values} ).put;'  

入力例:

a 12
a 13
a 15
a 14
b 5
b 6
c 2
c 5

出力例:

a   12 13 15 14
b   5 6
c   2 5

以下はコーディングされたソリューションです。幸せ、Perl プログラミング言語ファミリーのメンバーです。上記のコードは、2列リストの(簡単な)ケースを処理します(以下のより一般的なソリューションの説明)。

より一般的な解決策(複数の列入力を含む)の場合は、lines行ごとに読み込み、words合計の要素をappendハッシュで分割し%h=>(太い矢印)ハッシュコンストラクタを使用してキー(左)と値(右)を描画します。特別な割り当て演算子を使用すると、.=最初に別々に宣言するステップは省略されます。my %h;その後、hashをclassify使用して戻り値を記録します(そうでない場合は、キーと値のペア全体が返されます)。%hkey:as

raku -e 'my %h.=append(.words[0] => .words[1..*]) for lines;  %h.classify(*.keys, :as{$_.values}).put;' 

warpbreaksRプログラミング言語のデータ(54行、3列)などの小さなデータセットに対して上記のコードを実行します。ここで、2番目の列は2つのタイプのウール、「」とAB」を表します。

  • [入力ファイルは次のとおりです。withwarpbreaksを使用してエクスポートされたデータセット、二重引用符を削除するための後処理、コンマをタブに変換]。Rwrite.csvrow.names=FALSE

以下で作業しているRakuコード(および戻り)。 -edキー以外の列 valueを使用する方法(または同じ結合を使用する方法)に注意してください。join"|"join(",")

~$ raku -e 'my %h.=append(.words[1] => .words[0,2].join("|") ) for lines.skip(1);  %h.classify(*.keys, :as{$_.values}).put;'  warpbreaks_no_quotes.tsv
A   26|L 30|L 54|L 25|L 70|L 52|L 51|L 26|L 67|L 18|M 21|M 29|M 17|M 12|M 18|M 35|M 30|M 36|M 36|H 21|H 24|H 18|H 10|H 43|H 28|H 15|H 26|H
B   27|L 14|L 29|L 19|L 29|L 31|L 41|L 20|L 44|L 42|M 26|M 19|M 16|M 39|M 28|M 21|M 39|M 29|M 20|H 21|H 24|H 17|H 13|H 15|H 15|H 16|H 28|H

https://stat.ethz.ch/R-manual/R-devel/library/datasets/html/warpbreaks.html
https://docs.raku.org/routine/classify
https://raku.org

答え4

awkの連想配列を使用する方が簡単なオプションかもしれません。

$ awk '{k[$1]=k[$1]" "$2} END {for (i in k) print i k[i]}' infile 
a 12 13 15 14
b 5 6
c 2 5

関連情報