문제

Given the output of 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(-)

I wanted to produce the sum of the numeric columns but preserve the formatting of the line. In the interest of generality, I produced this awk script that automatically sums any numeric columns and produces a summary line:

{
    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
}

Yielding:

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

Awk has several features that simplify the problem, like automatic string->number conversion, all arrays as associative arrays, and the ability to overwrite auto-split positional parameters and then print the equivalent lines.

Is there a better language for this hack?

도움이 되었습니까?

해결책

Perl - 47 char

Inspired by ChristopheD's awk solution. Used with the -an command-line switch. 43 chars + 4 chars for the command-line switch:

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

I can get it to 45 (41 + -ap switch) with a little bit of cheating:

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

Older, hash-based 66 char solution:

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

다른 팁

Ruby — 87

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

Python - 101 chars

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

Using reduce is longer at 126 chars

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)))

AWK - 63 characters

(in a bash script, $1 is the filename provided as command line argument):

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

One could of course also pipe the input in (would save another 3 characters when allowed).

This problem is not challenging or difficult... it is "cute" though.

Here is solution in 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))

What does it do... it keeps tally in r while proceeding line by line. Splits the line, then for each element of the list, if it is a number, adds it to the tally or keeps it as string. At the end they all get re-mapped to string and merged with spaces in between to be printed.

Alternative, more "algebraic" implementation, if we did not care about reading all input at once:

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))))

What does this one do? totalize() takes a list of strings and tries to calculate sum of the numbers; if that fails, it simply returns the last one. zip() is fed with a matrix that is list of rows, each of them being list of column items in the row - zip transposes the matrix so it turns into list of column items and then totalize is invoked on each column and the results are joined as before.

At the expense of making your code slightly longer, I moved the main parsing into the BEGIN clause so the main clause is only processing numeric fields. For a slightly larger input file, I was able to measure a significant improvement in speed.

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
}

I made a test file using your data and doing paste file file file ... and cat file file file ... so that the result had 147 fields and 1960 records. My version took about 1/4 as long as yours. On the original data, the difference was not measurable.

JavaScript (Rhino) - 183 154 139 bytes

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])

Readable-ish:

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]);

PHP 152 130 Chars

Input:

$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(-)";

Code:

$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]";

Output:

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

Note: explode() will require that there is a space char before the new line.

Haskell - 151 135 bytes

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

... but I'm sure it can be done better/smaller.

Lua, 140 bytes

I know Lua isn't the best golfing language, but compared by the size of the runtimes, it does pretty well I think.

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})

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);

This would, however, require the whole input in $i... A variant with $i replaced with $_POST["i"] so it would be sent in a textarea... Has 162 chars:

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);

This is a version with

NO HARDCODED COLUMNS

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top