自动汇总数字列和打印总数

时间:2010-11-17 23:51:56

标签: language-agnostic awk code-golf

考虑git ... --stat的输出:

 3 files changed, 72 insertions(+), 21 deletions(-)
 3 files changed, 27 insertions(+), 4 deletions(-)
 4 files changed, 164 insertions(+), 0 deletions(-)
 9 files changed, 395 insertions(+), 0 deletions(-)
 1 files changed, 3 insertions(+), 2 deletions(-)
 1 files changed, 1 insertions(+), 1 deletions(-)
 2 files changed, 57 insertions(+), 0 deletions(-)
 10 files changed, 189 insertions(+), 230 deletions(-)
 3 files changed, 111 insertions(+), 0 deletions(-)
 8 files changed, 61 insertions(+), 80 deletions(-)

我想生成数字列的总和但保留行的格式。 为了一般性,我制作了这个awk脚本,它自动汇总任何数字列并生成摘要行:

{
    for (i = 1; i <= NF; ++i) {
        if ($i + 0 != 0) {
            numeric[i] = 1;
            total[i] += $i;
        }
    }
}
END {
    # re-use non-numeric columns of last line
    for (i = 1; i <= NF; ++i) {
        if (numeric[i])
            $i = total[i]
    }
    print
}

产量:

 44 files changed, 1080 insertions(+), 338 deletions(-)

Awk有几个简化问题的功能,例如自动字符串 - &gt;数字转换,所有数组作为关联数组,以及覆盖自动拆分位置参数然后打印等效行的功能。

这个黑客有更好的语言吗?

11 个答案:

答案 0 :(得分:5)

Perl - 47 char

受ChristopheD的awk解决方案的启发。与-an命令行开关一起使用。 43个字符+ 4个字符用于命令行开关:

$i-=@a=map{($b[$i++]+=$_)||$_}@F}{print"@a"

我可以通过一点点作弊来达到45(41 + -ap开关):

$i=0;$_="Ctrl-M@{[map{($b[$i++]+=$_)||$_}@F]}"

旧的,基于散列的66字符解决方案:

@a=(),s#(\d+)(\D+)#$b{$a[@a]=$2}+=$1#gefor<>;print map$b{$_}.$_,@a

答案 1 :(得分:2)

Python - 101个字符

import sys
print" ".join(`sum(map(int,x))`if"A">x[0]else x[0]for x in zip(*map(str.split,sys.stdin)))'

在126个字符处使用reduce更长

import sys
print" ".join(reduce(lambda X,Y:[str(int(x)+int(y))if"A">x[0]else x for x,y in zip(X,Y)],map(str.split,sys.stdin)))

答案 2 :(得分:2)

Ruby - 87

puts ' '+[*$<].map(&:split).inject{|i,j|[0,3,5].map{|k|i[k]=i[k].to_i+j[k].to_i};i}*' '

答案 3 :(得分:2)

AWK - 63个字符

(在bash脚本中,$ 1是作为命令行参数提供的文件名):

awk -F' ' '{x+=$1;y+=$4;z+=$6}END{print x,$2,$3,y,$5,z,$7}' $1

当然也可以输入输入(如果允许则会另外保存3个字符)。

答案 4 :(得分:1)

这个问题没有挑战性或困难......但它很“可爱”。

以下是Python中的解决方案:

import sys
r = []
for s in sys.stdin:
    r = map(lambda x,y:(x or 0)+int(y) if y.isdigit() else y, r, s.split())
print ' '.join(map(str, r))

它做了什么......它在逐行前进时保持在r中。拆分该行,然后对于列表的每个元素,如果它是一个数字,则将其添加到计数或将其保留为字符串。最后,它们都被重新映射到字符串并与之间的空格合并以进行打印。

如果我们不关心一次读取所有输入,可选择更多“代数”实现:

import sys

def totalize(l):
    try:    r = str(sum(map(int,l)))
    except: r = l[-1]
    return r

print ' '.join(map(totalize, zip(*map(str.split, sys.stdin))))

这个人做了什么? totalize()获取字符串列表并尝试计算数字的总和;如果失败,它只返回最后一个。 zip()提供了一个行列表矩阵,每个行都是行中列项的列表 - zip转置矩阵,使其变为列项列表,然后调用totalize每列和结果都像以前一样加入。

答案 5 :(得分:1)

以使代码稍长一些为代价,我将主解析移动到BEGIN子句中,因此main子句只处理数字字段。对于稍微大一点的输入文件,我能够测量速度的显着提高。

BEGIN {
    getline
    for (i = 1; i <= NF; ++i) {
        # need to test for 0, too, in this version
        if ($i == 0 || $i + 0 != 0) {
            numeric[i] = 1;
            total[i] = $i;
        }
    }
}
{
    for (i in numeric) total[i] += $i
}
END {
    # re-use non-numeric columns of last line
    for (i = 1; i <= NF; ++i) {
        if (numeric[i])
            $i = total[i]
    }
    print
}

我使用您的数据创建了一个测试文件并执行paste file file file ...cat file file file ...,以便结果有147个字段和1960个记录。我的版本大约占你的1/4。在原始数据上,差异无法衡量。

答案 6 :(得分:1)

JavaScript(Rhino) - 183 154 139字节

Golfed:

x=[n=0,0,0];s=[];readFile('/dev/stdin').replace(/(\d+)(\D+)/g,function(a,b,c){x[n]+=+b;s[n++]=c;n%=3});print(x[0]+s[0]+x[1]+s[1]+x[2]+s[2])

可读肥胖型:

x=[n=0,0,0];
s=[];

readFile('/dev/stdin').replace(/(\d+)(\D+)/g,function(a,b,c){
    x[n]+=+b;
    s[n++]=c;
    n%=3
});

print(x[0]+s[0]+x[1]+s[1]+x[2]+s[2]);

答案 7 :(得分:1)

PHP 152 130 Chars

输入:

$i = "
3 files changed, 72 insertions(+), 21 deletions(-) 
3 files changed, 27 insertions(+), 4 deletions(-) 
4 files changed, 164 insertions(+), 0 deletions(-) 
9 files changed, 395 insertions(+), 0 deletions(-) 
1 files changed, 3 insertions(+), 2 deletions(-) 
1 files changed, 1 insertions(+), 1 deletions(-) 
2 files changed, 57 insertions(+), 0 deletions(-) 
10 files changed, 189 insertions(+), 230 deletions(-) 
3 files changed, 111 insertions(+), 0 deletions(-) 
8 files changed, 61 insertions(+), 80 deletions(-)";

代码:

$a = explode(" ", $i);

foreach($a as $k => $v){
    if($k % 7 == 0)
        $x += $v;

    if(3-$k % 7 == 0)
        $y += $v;

    if(5-$k % 7 == 0)
        $z += $v;   

}

echo "$x $a[1] $a[2] $y $a[4] $z $a[6]";

输出:

44 files changed, 1080 insertions(+), 338 deletions(-)

注意:explode()将要求在新行之前有空格char。

答案 8 :(得分:0)

Haskell - 151 135字节

import Char
c a b|all isDigit(a++b)=show$read a+read b|True=a
main=interact$unwords.foldl1(zipWith c).map words.filter(not.null).lines

......但我确信它可以做得更好/更小。

答案 9 :(得分:0)

Lua,140字节

我知道Lua不是最好的高尔夫语言,但通过运行时的大小进行比较,我觉得它确实很好。

f,i,d,s=0,0,0,io.read"*a"for g,a,j,b,e,c in s:gmatch("(%d+)(.-)(%d+)(.-)(%d+)(.-)")do f,i,d=f+g,i+j,d+e end print(table.concat{f,a,i,b,d,c})

答案 10 :(得分:0)

PHP, 176 166 164 159 158 153

for($a=-1;$a<count($l=explode("
",$i));$r=explode(" ",$l[++$a]))for($b=-1;$b<count($r);$c[++$b]=is_numeric($r[$b])?$c[$b]+$r[$b]:$r[$b]);echo join(" ",$c);

然而,这将需要 $ i 中的整个输入... $ _ 的变体替换为 $ _ POST [“i”] < / em>所以它将在textarea中发送... 162 字符:

for($a=-1;$a<count($l=explode("
",$_POST["i"]));$r=explode(" ",$l[$a++]))for($b=0;$b<count($r);$c[$b]=is_numeric($r[$b])?$c[$b]+$r[$b]:$r[$b])$b++;echo join(" ",$c);

这是

的版本

无HARDCODED COLUMNS