sed 或 awk:按 2 列分组并获取另一列的最后一个值
sed or awk : group by 2 columns and get the last value of another column
我需要快速处理一个包含大量冗余的文本文件。
我可以使用 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
考虑到您的 Input_file 与所示示例相同,并且在第一个和第三个字段的排序方法中,以下内容可能会对您有所帮助。
awk '
FNR==1{
print;
next
}
!a[,]++{
if(a[prev]){
print prev,a[prev]};
a[,]=
}
{
prev= FS
}
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
你可以使用这个awk
:
awk '{key= FS } !(key in arr){a[++n]=key} {arr[key]=}
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
有一个专门用于此类任务的工具 - datamash
:
部分解决方案,没有 header:
datamash -W -t' ' --header-in -g 1,3 last 2 < input.txt
为了简化演示代码,放弃了 header 1,2,3
,因为它有另一个字段分隔符,而不是其他行,这使任务复杂化。
说明
-W, --whitespace
- 使用空格(一个或多个空格 and/or 制表符)作为字段分隔符。
-t, --field-separator=X
- 使用 X 而不是 TAB 作为字段分隔符。
--header-in
- 第一个输入行是列 headers(在我们的例子中,我们这样做只是为了省略 header)。
-g, --group=X[,Y,Z]
- 通过字段分组 X,[Y,Z]
.
last
- 组的最后一个值。
输出
a A 3
b C 3
b D 3
c C 1
c D 2
完整的解决方案,其中保留了 header:
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
使用 tac
和 GNU sort
。
$ tac Group_Data | sort -u -k1,1 -k3 | awk '{if (NR == 1) print [=10=]; else print ,,}'
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
我需要快速处理一个包含大量冗余的文本文件。 我可以使用 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
考虑到您的 Input_file 与所示示例相同,并且在第一个和第三个字段的排序方法中,以下内容可能会对您有所帮助。
awk '
FNR==1{
print;
next
}
!a[,]++{
if(a[prev]){
print prev,a[prev]};
a[,]=
}
{
prev= FS
}
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
你可以使用这个awk
:
awk '{key= FS } !(key in arr){a[++n]=key} {arr[key]=}
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
有一个专门用于此类任务的工具 - datamash
:
部分解决方案,没有 header:
datamash -W -t' ' --header-in -g 1,3 last 2 < input.txt
为了简化演示代码,放弃了 header 1,2,3
,因为它有另一个字段分隔符,而不是其他行,这使任务复杂化。
说明
-W, --whitespace
- 使用空格(一个或多个空格 and/or 制表符)作为字段分隔符。-t, --field-separator=X
- 使用 X 而不是 TAB 作为字段分隔符。--header-in
- 第一个输入行是列 headers(在我们的例子中,我们这样做只是为了省略 header)。-g, --group=X[,Y,Z]
- 通过字段分组X,[Y,Z]
.last
- 组的最后一个值。
输出
a A 3
b C 3
b D 3
c C 1
c D 2
完整的解决方案,其中保留了 header:
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
使用 tac
和 GNU sort
。
$ tac Group_Data | sort -u -k1,1 -k3 | awk '{if (NR == 1) print [=10=]; else print ,,}'
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