根据另一列减去一列中的值

时间:2016-12-28 16:59:54

标签: awk

我输入文件如下

100A 2000
100B 150
100C 800
100A 1000
100B 100
100C 300

我想在第1列中为第1列中的每个uniq值减去值 因此输出应该看起来像

100A 1000
100B 50
100C 500

我试过了

 awk '{if(!a[$1])a[$1]=$2; else a[$1]=$2-a[$1]}END{ for(i in a)print i" " a[i]}' file 

但输出的是:

100A 0
100B 0
100C 0

请告知

5 个答案:

答案 0 :(得分:2)

同一主题有很多(轻微)变化。

awk '
  !($1 in a) {a[$1]=$2; next}
  {a[$1]-=$2}
  END {for (i in a) printf "%s %d\n",i,a[i]}
' input.txt

如果你愿意,可以将它叠加成一行。

请记住,awk结构由多个condition { statement }对组成,因此您有时可以比使用if..else更优雅地表达您的要求。 (并不是说这就是这种情况 - 这是一个简单的awk脚本,它可能无关紧要,除非你是一个纯粹主义者。:])

另外,请注意在问题中if的条件下按照您的方式测试值。请注意a[$1] 两者测试该数组索引处的值是否为非导致索引以空值存在(如果之前不存在)存在。如果要检查索引是否存在,请使用$1 in a

根据您对问题的评论进行更新...

如果你想从第一个条目中减去 last ,忽略其间的那些,那么你需要记录你的第一次和你的持续时间。这样的事情就足够了。

awk '
  !($1 in a){a[$1]=$2;next}
  {b[$1]=$2}
  END {for(i in b)if(i in a)print i,a[i]-b[i]}
' input.txt

请注意,如Ed所述,这会以随机顺序生成输出。如果您希望输出有序,则需要一个额外的数组来跟踪订单。例如,这将使用首次看到项目的顺序:

awk '
  !($1 in a) {
    a[$1]=$2;
    o[++n]=$1;
    next
  }
  {
    b[$1]=$2
  }
  END {
    for (n=1;n<=length(o);n++)
      print o[n],a[o[n]]-b[o[n]]
  }
' i

请注意,用于确定数组中元素数量的length()函数在awk的方言中并不普遍,但它在gawk和one-true-awk中都有效(在FreeBSD和其他方面使用) )。

答案 1 :(得分:1)

这个awk one-liner完成了这项工作:

 awk '{if($1 in a)a[$1]=a[$1]-$2;else a[$1]=$2}
      END{for(x in a) print x, a[x]}' file

答案 2 :(得分:1)

在awk中。使用条件运算符进行值放置/减法以保持紧密:

$ awk '{ a[$1]+=($1 in a?-$2:$2) } END{ for(i in a)print i, a[i] }' file
100A 1000
100B 50
100C 500

说明:

{ 
    a[$1]+=($1 in a?-$2:$2)  # if $1 in a already, subtract from it 
                                # otherwise add value to it
} 
END { 
    for(i in a)              # go thru all a
        print i, a[i]          # and print keys and values
}

答案 3 :(得分:1)

根据您提供的样本输入,您只需要:

$ awk '$1 in a{print $1, a[$1]-$2} {a[$1]=$2}' file
100A 1000
100B 50
100C 500

如果这不是您所需要的,那么提供更具真实代表性的样本输入/输出,其中包括那些不够好的情况。

答案 4 :(得分:0)

您可以使用此awk

awk 'a[$1]{a[$1]=a[$1]-$2; next} {a[$1]=$2} END{for(v in a){print v, a[v]}}' file