3

私は過去数日間、次のデータを非常にすばやく転置できる一連のコマンドラインツール、perlまたはawkスクリプトを探していました。

Row|Col|Val
1|A|foo
1|B|bar
1|C|I have a real
2|A|bad
2|C|hangover

これに:

A|B|C
foo|bar|I have a real
bad||hangover

データセットには、各「セル」の値が1つしかないことに注意してください(つまり、スプレッドシートの場合と同様に、行「1」、列「A」の重複はありません)。

データを転置するためにさまざまなawkシェルの実装を試しましたが、それらを機能させることができないようです。私が持っていたアイデアの1つは、各「Col」値を個別のファイルに切り取り、「join」コマンドラインを使用して「Row」で元に戻すことでしたが、もっと簡単な方法が必要です。これは非常に簡単に実行できると確信していますが、少し苦労しています。

私の入力ファイルには、列AからG(主に可変長の文字列を含む)と10,000行があります。すべてをメモリにロードすることを避けることができれば、それは大きなプラスになります。

答えがわかれば誰でもメールでビール!

いつものように-あなたの助けに前もって感謝します。

乾杯、

ジョシュ

ps-この非常に基本的なタイプのピボット/転置操作を実行するためのすぐに使用できるコマンドラインユーティリティがないことに少し驚いています。http://code.google.com/p/openpivot/http://code.google.com/p/crush-tools/を調べましたが、どちらも集計計算が必要なようです。

4

3 に答える 3

3

これはgawkで実行できますが、nawkでは実行できません。

#!/usr/local/bin/gawk -f

BEGIN {
  FS="|";
}

{
  rows[$1]=1; cols[$2]=1; values[$1][$2]=$3;
}

END {
  for (col in cols) {
    output=output sprintf("|%s", col);
  }
  print substr(output, 2);
  for (row in rows) {
    output="";
    for (col in cols) {
      output=output sprintf("|%s", values[row][col]);
    }
    print substr(output, 2);
  }
}

そしてそれも機能します:

ghoti@pc $ cat data
1|A|foo
1|B|bar
1|C|I have a real
2|A|bad
2|C|hangover
ghoti@pc $ ./doit.gawk data
A|B|C
foo|bar|I have a real
bad||hangover
ghoti@pc $ 

これが10000行でどれだけうまく機能するかはわかりませんが、メモリがあれば大丈夫だと思います。後で参加する別のファイルに保存する以外に、メモリへの読み込みを回避する方法がわかりません。これは、仮想メモリのほとんど手動の実装です。

アップデート:

コメントごと:

#!/usr/local/bin/gawk -f

BEGIN {
  FS="|";
}

{
  rows[$1]=1; cols[$2]=1; values[$1,$2]=$3;
}

END {
  for (col in cols) {
    output=output sprintf("|%s", col);
  }
  print output;
  for (row in rows) {
    output="";
    for (col in cols) {
      output=output "|" values[row,col];
    }
    print row output;
  }
}

そして出力:

ghoti@pc $ ./doit.awk data
|A|B|C
1|foo|bar|I have a real
2|bad||hangover
ghoti@pc $ 
于 2012-02-28T04:17:15.763 に答える
1

ハッシュを使用するだけです。それらをメモリにロードしたくない場合はDBM::Deep、DBMバックエンドなどのモジュールが必要になる場合があります。

my %table;

my $maxa = 'A';
my $maxr = 0;

<>;

while (<>) {
    chomp;
    my ($a,$b,$c) = split /\|/;
    $table{$a}->{$b} = $c;

    $maxr = $a if ($a > $maxr);
    $maxa = $b if ($b gt $maxa);
}

for (my $c = 'A' ; $c lt $maxa ; $c++) {
    print $c . '|';
}
print "$maxa\n";

for (my $r = 1 ; $r <= $maxr ; $r++) {
    for (my $c = 'A' ; $c lt $maxa ; $c++) {
        print $table{$r}->{$c} . '|';
    }
    print $table{$r}->{$maxa} . "\n";
}
于 2012-02-28T03:26:02.650 に答える
1

Awkをご存知の場合は、Perlをご覧になることをお勧めします。PerlはAwkよりもはるかに強力です。利点は、BASH / BourneシェルとAwkを知っていれば、Perlの構文の多くに精通していることです。

Perlのもう1つの優れた点は、CPANリポジトリ全体です。これにより、プログラムで使用するために、すでに作成されたPerlモジュールをダウンロードできます。CPANですばやく検索すると、(非常に一見すると)希望どおりの結果が得られるように見えるData::Pivotが表示されます。

そうでない場合は、Acme::Toolsのピボットコマンドをご覧ください。または、他の多くの1つを試してください。

他の人はすでにいくつかの解決策を提供していますが、CPANPerlアーカイブが何を持っているかを確認することをお勧めします。これは、このようなもののための非常に強力なツールです。

于 2012-02-28T04:33:28.807 に答える