質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

バッチファイル

バッチファイル(Batch File)は、Windowsのコマンドラインインタープリターによって複数のコマンドを実行させる事が出来るスクリプトファイルです。

AWK

AWKは、UNIX 上で開発されたプログラミング言語で、CSVファイルなどのテキストファイルの処理を目的にデザインされています。

Q&A

解決済

4回答

1468閲覧

【awk】同一キーのレコード数のフィールドを各レコードに追加する(csvファイル)

dos_1980_bat

総合スコア6

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

バッチファイル

バッチファイル(Batch File)は、Windowsのコマンドラインインタープリターによって複数のコマンドを実行させる事が出来るスクリプトファイルです。

AWK

AWKは、UNIX 上で開発されたプログラミング言語で、CSVファイルなどのテキストファイルの処理を目的にデザインされています。

0グッド

0クリップ

投稿2020/02/26 09:37

・キー(フィールド1)でsort済みのcsvデータ

・同一キーのレコード数の入ったフィールドを、各レコードに追加したい

~例えば、キーaが4レコードあれば、最後尾にレコード数”4”のフィールドを追加する

・windows7のコマンドプロンプトにて、gawkスクリプトを利用しています

入力csvファイル

*** testin.csv
a,123
a,1
a,12
a,23
b,13
b,12
c,23
c,123
c,1
c,1

出力させたいcsvファイル

*** testout.csv
a,123,4
a,1,4
a,12,4
a,23,4
b,13,2
b,12,2
c,23,4
c,123,4
c,1,4
c,1,4

ソースコード

*** test.awk

BEGIN{
FS=OFS=",";
COUNT=1;
table[COUNT]=$0;KIOKU=$1}
{
if (KIOKU!=$1){
i=1;
while(i<=COUNT){print table[i],COUNT;i++;}
COUNT=1;
table[COUNT]=$0;KIOKU=$1;}
else {
COUNT++;
table[COUNT]=$0}
}
END{
if (NR>0)
{i=1;while(i<=COUNT){print table[i],COUNT;i++;}
}

*** test.cmd
gawk -f "test.awk" testin.csv > testout.csv

試したこと

・レコードはいったん配列に格納、キー変化したら格納した配列からレコード吐き出す、という作戦でした。

現状・教えていただきたいこと

・出力ループの書き方等、自信ありません
(テスト繰り替えして、ようやく行きついた感じです)
・実際に動かすと1行目にゴミがでてしまいます。
・出力後、配列をクリアしていませんが、問題ないでしょうか?

初歩的な質問で恐縮です。
よろしくお願いいたします。

*** 実際の testout.csv
,1         <<== ゴミ
a,123,4
a,1,4
a,12,4
a,23,4
b,13,2
b,12,2
c,23,4
c,123,4
c,1,4
c,1,4

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

参加のみです。書き方色々ありますね
awk -F, '{if(NF==1){sv=$1;i=0};
if(sv==$1){ar[i++]=$0}
else{for(j=0;j<i;j++)print ar[j]","i;i=0;ar[i++]=$0;};sv=$1}
END{for(j=0;j<i;j++)print ar[j]","i;}'

投稿2020/02/26 22:59

編集2020/02/26 23:02
amura

総合スコア333

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dos_1980_bat

2020/02/27 03:58

amura様 回答ありがとうございました。 回答いただいたソースでうまく動きました(スクリプト化して走らせました)。 ご指導ありがとうございました。
guest

0

現状のソースを活かすならこんなかんじでしょか

BEGIN { FS = OFS = ","; KIOKU = ""; COUNT = 0; } { if (KIOKU != $1 && KIOKU != "") { for (i = 1; i <= COUNT; i++) { print table[i],COUNT; } COUNT = 1; } else { COUNT++; } table[COUNT] = $0; KIOKU = $1; } END{ if (COUNT > 0) { for (i = 1; i <= COUNT; i++) { print table[i],COUNT; } } }

投稿2020/02/26 11:08

takasima20

総合スコア7458

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dos_1980_bat

2020/02/27 03:58

takasima20様 回答ありがとうございました。 修正いただいたソースで、うまく動きました。 BEGINブロックの処理について正しく理解していませんでした。 「キー変化で配列から出力」としたことが、処理を複雑にしていることも学びました。 ご指導ありがとうございました。
guest

0

さきほど回答したものですが、質問者さんのスクリプトについての回答を別回答としてあらためて書きます。

・実際に動かすと1行目にゴミがでてしまいます。

・BEGINブロックは入力ファイルを処理する前に1回だけ実行されるものなので、
ここに$0とか$1とか書いても何も入っていないと思います。
変数KIOKUにキーとしてはありえない値で初期化しておけば良いと思います。
BEGINブロックの中を以下のように修正したら1行目のゴミは出なくなりました。

・出力後、配列をクリアしていませんが、問題ないでしょうか?

スクリプト内の変数や配列は、スクリプト実行後(awkプロセスの終了後)は消えてしまうものなので
問題ないと思います。

awk

1#! /usr/bin/awk -f 2BEGIN{ 3 FS=OFS=","; 4 #COUNT=1; 5 #table[COUNT]=$0; 6 #KIOKU=$1 7 KIOKU="キーとしてはありえない文字列" 8 COUNT=0 9} 10{ 11 if (KIOKU!=$1){ 12 i=1; 13 while(i<=COUNT) { 14 print table[i],COUNT; 15 i++; 16 } 17 COUNT=1; 18 table[COUNT]=$0; 19 KIOKU=$1;} 20 else { 21 COUNT++; 22 table[COUNT]=$0 23 } 24} 25END{ 26 if (NR>0) { 27 i=1; 28 while(i<=COUNT){ 29 print table[i],COUNT;i++; 30 } 31 } 32} 33

投稿2020/02/26 11:08

編集2020/02/26 11:32
hidezzz

総合スコア1248

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dos_1980_bat

2020/02/27 03:56

hidezzz様 回答ありがとうございました。 修正いただいたソースで、うまく動きました。 ・BEGINブロックの処理について、理解していませんでした。 ・配列クリアについて~「キー変化した後、格納先の配列を初期化する必要があるか」という意味でしたが、ピントはずれの質問でした。大変失礼しました。 先のご回答と比較して「キー変化で配列から出力」としたことが、処理を複雑にしていることを学びました。ありがとうございました。
hidezzz

2020/02/27 18:16

> ・配列クリアについて~「キー変化した後、格納先の配列を初期化する必要があるか」という意味でしたが、ピントはずれの質問でした。大変失礼しました。 すみません。意味を取り違えてました。 table配列のどこまでが使われているかは、COUNT変数で把握しているはずなので、クリアしなくても特に問題は発生しないと思います。 ただ、クリアするようにするとデバッガで値を確認する際にやりやすくなるいうことはあるかもしれません。
guest

0

ベストアンサー

・入力ファイルの内容は配列recに格納する。
・フィード1をキーとして、連想配列cntに出現回数をカウントする。
・最後にENDブロックで結果出力する。
という感じで書いてみました。

とりあえず、1行で書いてみました。

terminal

1$ awk 'BEGIN{FS=","};{++cnt[$1];rec[++i]=$0};END{for(r in rec){$0=rec[r];print $0 "," cnt[$1]}}' testin.csv

次のものは1行で書いたものをスクリプトに展開しただけで同じものです。

awk

1#! /usr/bin/awk -f 2BEGIN{ 3 FS="," 4} 5{ 6 ++cnt[$1] 7 rec[++i]=$0 8} 9END{ 10 for(r in rec){ 11 $0=rec[r]; 12 print $0 "," cnt[$1] 13 } 14} 15

投稿2020/02/26 10:19

編集2020/02/26 10:31
hidezzz

総合スコア1248

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dos_1980_bat

2020/02/27 03:55

hidezzz様 回答ありがとうございました。 アドバイスいただいたソースでうまく動きました。 出力順を入力側と合わせたいと思い(ググりながら)forループの記述を少しいじってみました。 BEGIN{ FS="," } { ++cnt[$1] rec[++i]=$0 } END{ for(i=1;i<=length(rec);i++){ $0=rec[i]; print $0 "," cnt[$1] } } 今の自分では思いつかない、シンプルなやり方で大変勉強になりました。 今後とも、ご指導よろしくお願いします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問