sed或awk:按2列分组并获取另一列的最后一个值

时间:2018-02-02 17:16:16

标签: shell awk sed group-by aggregation

我需要快速处理一个有很多冗余的文本文件。 我可以使用python,但我认为最简单,最快的将是在unix shell中使用awk,sed或perl。

数据有3列,我需要按(唯一)第1列和第3列分组,然后获取第2列的最后一个值

1,2,3
a 1 A
a 2 A
a 3 A
b 2 C
b 3 C
b 3 D
c 1 C
c 1 D
c 2 D

结果应该是:

1,2,3
a A 3
b C 3
b D 3
c C 1
c D 2

4 个答案:

答案 0 :(得分:1)

考虑到您的Input_file与显示的示例相同,并且在第一个和第三个字段的排序方法中,以下可能会帮助您。

awk '
FNR==1{
  print;
  next
}
!a[$1,$3]++{
  if(a[prev]){
    print prev,a[prev]};
  a[$1,$3]=$2
}
{
  prev=$1 FS $3
}
END{
  if(a[prev] && prev){
    print prev,a[prev]
}}
' SUBSEP=" "   Input_file

输出如下:

1,2,3
a A 3
b C 3
b D 3
c C 1
c D 2

答案 1 :(得分:1)

您可以使用此awk

awk '{key=$1 FS $3} !(key in arr){a[++n]=key} {arr[key]=$2}
END{for (i=1; i<=n; i++) print a[i], arr[a[i]]}' file

1,2,3
a A 3
b C 3
b D 3
c C 1
c D 2

答案 2 :(得分:1)

此类任务有一个特殊工具 - datamash

部分解决方案,没有标题:

datamash -W -t' ' --header-in -g 1,3 last 2 < input.txt

标头1,2,3被丢弃以简化演示代码,因为它有另一个字段分隔符,而不是其他行,这使得任务复杂化。

<强>解释

  • -W, --whitespace - 使用空格(一个或多个空格和/或制表符)作为字段分隔符。

  • -t, --field-separator=X - 使用X代替TAB作为字段分隔符。

  • --header-in - 第一个输入行是列标题(在我们的例子中,我们这样做只是为了省略标题)。
  • -g, --group=X[,Y,Z] - 通过字段X,[Y,Z]分组。
  • last - 该组的最后一个值。

<强>输出

a A 3
b C 3
b D 3
c C 1
c D 2

完整的解决方案,保留标题:

cat <(head -n 1 input.txt) <(tail -n +2 input.txt | datamash -W -t' ' -g 1,3 last 2)

<强>输出

1,2,3
a A 3
b C 3
b D 3
c C 1
c D 2

答案 3 :(得分:0)

使用tac和GNU sort

$ tac Group_Data | sort -u -k1,1 -k3 | awk '{if (NR == 1) print $0; else print $1,$3,$2}'
1,2,3
a A 3
b C 3
b D 3
c C 1
c D 2

IMO python词典和强大的sorted功能使得python像其他任何类似的解决方案一样快速和有竞争力,特别是如果您将使用python进一步处理下游数据。在项目下面将它们用作Python字典的键,然后按第一和第二元素排序。

>>> groupdict = {}
>>> with open("Group_Data") as fp:
...     for ii, lines in enumerate(fp):
...         if ii == 0:
...             header = lines.rstrip()
...         else:
...             fields = lines.split()
...             groupdict[(fields[0],fields[2])] = fields[1]
... 
>>> groupdict
{('b', 'C'): '3', ('a', 'A'): '3', ('c', 'D'): '2', ('c', 'C'): '1', ('b', 'D'): '3'}
>>> for ii,elem in enumerate(sorted(groupdict.items(), key = lambda x : (x[0],x[1]))):
...     if ii == 0:
...         print header
...     key, value = elem
...     print key[0],key[1],value
... 
1,2,3
a A 3
b C 3
b D 3
c C 1
c D 2