【问题标题】:awk - add values from field based on another fieldawk - 根据另一个字段从字段中添加值
【发布时间】:2017-11-30 08:37:15
【问题描述】:

这个问题不完整,因为我找不到简洁的表达方式。我有这些数据:

Location   Group   Device#
--------------------------
location1  group01  10
location2  group10   8
location2  groupxx   7
location3  groupAA  11

期望的输出:

Location   Group   Device#   Total_Device#
------------------------------------------
location1  group01  10       10
location2  group10   8       15
location2  groupxx   7       15
location3  groupAA  11       11

我已经阅读了一些关于如何根据每个唯一 Location 求和的解决方案,但我希望将结果显示为“重复”,因为一个位置可以有 2 个或更多组,我想将每个组显示为好吧。

【问题讨论】:

  • 您是否要求纯粹的awk 解决方案或其他(bashsqlite、...)也可以接受?
  • 假设bash 也会很有趣,但我怀疑它是否可以像下面的awk 回答一样优雅地完成:)

标签: bash awk


【解决方案1】:

输入

$ cat infile
Location   Group   Device#
--------------------------
location1  group01  10
location2  group10   8
location2  groupxx   7
location3  groupAA  11

通过读取文件输出

$ awk  'NR==1{print $0,"Total_Device#"}NR==2{print $0"--"}NR>2{a[$1]+=$NF; b[i++] = $0}END{for(i in b){split(b[i],d);print b[i],a[d[1]]}}' infile
Location   Group   Device# Total_Device#
----------------------------
location1  group01  10 10
location2  group10   8 15
location2  groupxx   7 15
location3  groupAA  11 11

说明

awk  '                                        # call awk
      NR==1{                                  # when awk reads first record
           print $0,"Total_Device#"           # print current record/row with extra field
      }
      NR==2{                                  # when awk reads second record
           print $0"--"                       # print current record with extra string
      }
      NR>2{                                   # if no of records greater than 2 
            a[$1]+=$NF;                       # sum up last field based on location where array is a
            b[i++] = $0                       # save row in array b 
      }
      END{
            for(i in b){                      # loop through array b
                 split(b[i],d);               # split array value where separator being field separator
                 print b[i],a[d[1]]           # print row and location sum
            }
      }' infile

通过两次读取同一个文件输出

$ awk  'FNR==NR{if(NR>2){loc[$1]+=$NF};next}FNR==1{print $0,"Total_Device#";next}{print $0,loc[$1]}' infile infile
Location   Group   Device# Total_Device#
-------------------------- 
location1  group01  10 10
location2  group10   8 15
location2  groupxx   7 15
location3  groupAA  11 11

说明

awk  '                                        # call awk
      FNR==NR{                                # this is true when awk reads first file
              if(NR>2){                       # if no of records is greater than 2
                 loc[$1]+=$NF                 # sum up last field based on 1st field
              }
              next                            # go to next record, because of this keyword rest of the code will be skipped
      } 
                                              # here we read same file second time
      FNR==1{                                 # if no of records corresponding to current file is equal to one
              print $0,"Total_Device#";       # print current record/row and extra field
              next                            # go to next line
      }
      { 
              print $0,loc[$1];               # print current record and sum which is available in array loc

      }
   ' infile infile

【讨论】:

  • 您的解决方案也有效,我投了赞成票,但将 Blaf 的解决方案标记为已接受的答案,因为我认为它更优雅、更灵活,可以进一步处理。谢谢!
【解决方案2】:

假设制表符分隔的列。

文件tot.awk

BEGIN{
   # set output separator
   OFS="\t"
}
NR==1{
   # print extended header
   print $0, "Total_Device#"
}
NR==2{
   # print header separator
   print
}
NR>2{
   # store original data in array
   loc[NR]=$1;
   grp[NR]=$2;
   cnt[NR]=$3;
   # store totals in associative array by location
   tot[$1]+=$3
}
END{
   # print each original line with calculated totals
   for (i=3; i<=NR; i++){
      print loc[i], grp[i], cnt[i], tot[loc[i]]
   }
}

输出:

> awk -f tot.awk data.txt
Location        Group   Device# Total_Device#
--------------------------
location1       group01 10      10
location2       group10 8       15
location2       groupxx 7       15
location3       groupAA 11      11

【讨论】:

  • 这是一种使用数组的非常优雅的方式,并且为进一步操作数据和打印结果保持了高度的灵活性。谢谢!
【解决方案3】:

一种可能性:

awk 'NR==FNR{if(/^location/){a[$1]+=$NF}next}{print $0, a[$1]}' your_file your_file

结果

Location   Group   Device# 
-------------------------- 
location1  group01  10 10
location2  group10   8 15
location2  groupxx   7 15
location3  groupAA  11 11

PD:我会把航向修正留给你。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-22
    • 2018-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多