One liner memo

また凝ってしまったので,メモ.

a 1 10
a 2 20
b 2 15
b 3 25
c 1 3
c 2 7
c 3 11
c 4 13

みたいに列,行,データと並ぶ入力から

,0,1,2,3,4
a,0,10,20,0,0
b,0,0,15,25,0
c,0,3,7,11,13

みたいな表を作る場合.

Excelとかでもできると思うんだけど,
やり方がわからないし,いろいろなデータ形式に対応するため,
One liner用の補助ツールを作ってみた.
# モジュール名がアレ何だけどね...

$ cat FN.pm
package FN;
use strict;
use warnings;
use base qw(Exporter);
our @EXPORT = qw(convMat getV);

sub getV(\%$$) { defined $_[0]->{$_[1]} ? $_[0]->{$_[1]} : $_[2] }
sub convMatPrint($$%) {
    my($prop, $keys, %attr) = @_;
    my $def = getV %attr, "def", 0;
    my $shw = getV %attr, "shw", 3;
    my $sep = getV %attr, "sep", ",";
    my($t1, $t2) = ($,, $\);
    ($,, $\) = ($sep, "\n");
    if(defined $prop->{"prev"}) {
        printf "%s%s", $prop->{"prev"}, $sep if($shw & 1);
        print map { getV %{$prop->{"cols"}}, $_, $def } @$keys;
    } elsif($shw & 2) {
        printf "%s", $sep if($shw & 1);
        print @$keys;
    }
    ($,, $\) = ($t1, $t2);
}
sub convMat(\%@) {
    my($prop, $keys, $row, $col, $val, %attr) = @_;
    if(!defined $prop->{"prev"} || $prop->{"prev"} ne $row) {
        convMatPrint($prop, $keys, %attr);
        $prop->{"prev"} = $row;
        $prop->{"cols"} = {};
    }
    $prop->{"cols"}{$col} = $val;
    convMatPrint($prop, $keys, %attr) if(eof);
}
1;

として,

$ perl -MFN -lane 'convMat %P,[0..4],@F[0..2]' <<EOF
a 1 10
a 2 20
b 2 15
b 3 25
c 1 3
c 2 7
c 3 11
c 4 13
EOF
,0,1,2,3,4
a,0,10,20,0,0
b,0,0,15,25,0
c,0,3,7,11,13

となる.ただし,データはあらかじめソートしておく必要がある.
まあ,sortを通せばすむ話だけど.

一応オプションとしてセパレータsep,デフォルト値def,
ヘッダーなんかの表示を変えるshw(0123)を用意した.


結構使う頻度あったし,毎回コード書くの面倒なので作ってみたけど,
簡単に変換するツールとかあったのかな...
ExcelとかRならできそうな気がするんだけど,あんま詳しくないからな...