如何在特定列上排序唯一性并打印第一个唯一的3位数字并添加第二个列的值

时间:2019-04-28 19:28:58

标签: awk

File.txt

chocolate,Paris,ER
milkchocolat,France,FR
berriesnoire,Paris,FR
chocolatewhite,Paris,FR
darkchocolat,Italy,IL
orange,usa,USA
plume,Paris,FR
milkshake,France,FR
orangebark,usa,USA

期望输出:

ber,Paris
cho,Paris
dar,Italy
mil,France
ora,usa
plu,paris

cat file.txt | awk -F”,” ‘{print $1”,”$2}’ | cut -c-3 | sort -u

此命令它只给我输出中的第一列

当前输出:

ber
cho
dar
mil
ora
plu

4 个答案:

答案 0 :(得分:3)

使用GNU sed进行排序:

sed -E 's/(...)[^,]*/\1/; s/,[^,]*$//' File.txt | sort -u

输出:

ber,Paris
cho,Paris
dar,Italy
mil,France
ora,usa
plu,Paris

请参阅:5.7 Back-references and Subexpressions

答案 1 :(得分:3)

对于每一行,将前三个字母与它们在数组记录中的出现次数相关联,并使用它来抑制重复项。因此,打印每个唯一记录的前三个字母和第二个字段。

awk 'BEGIN{FS=OFS=","} !seen[key=substr($1,1,3)]++{print key,$2}' file | sort

给出示例输入,输出如下:

ber,Paris
cho,Paris
dar,Italy
mil,France
ora,usa
plu,Paris

或者,使用任何sed和sort:

sed 's/\(...\)[^,]*\(,[^,]*\).*/\1\2/' file | sort -u

请注意,只有第一个字母的前三个字母是唯一的,第一个字母才会列出该记录。但是,如果第一列的前三个字母和整个第二列都是唯一的,则第二个将列出一条记录。

对于这样的输入:

chocolate,Paris
chocolate,paris

第一个人的输出将是:

cho,Paris

但第二个人的输出将是:

cho,Paris
cho,paris

由于您不清楚,我为这两种情况添加了解决方案,请使用满足您要求的解决方案。

答案 2 :(得分:3)

这是我的:

awk -F, '{printf "%.3s,%s\n", $1, $2}' data.txt | sort -u

答案 3 :(得分:1)

简单的 awk | 排序解决方案:

$ time awk -F, -v OFS=, '{ print substr($1, 1, 3), $2 }' file | sort -u
ber,Paris
cho,Paris
dar,Italy
mil,France
ora,usa
plu,Paris

real    0m0.007s
user    0m0.003s
sys     0m0.006s

我认为通过执行 awk 中的 -u 部分来保存IO会更快,但它等效或慢一点:

$ time awk -F, -v OFS=, -v SUBSEP=, '
    BEGIN { split("", a) }
          { a[substr($1, 1, 3), $2] = "" }
    END   { for (i in a) print i }
' file | sort
ber,Paris
cho,Paris
dar,Italy
mil,France
ora,usa
plu,Paris

real    0m0.007s
user    0m0.006s
sys     0m0.004s

但是在具有asorti()实现的 awk 版本中,放弃管道并完成整个过程要快一些:

$ time gawk -F, -v OFS=, -v SUBSEP=, '
    BEGIN { split("", a) }
          { a[substr($1, 1, 3), $2] = "" }
    END   { N = asorti(a); for (i=1; i<=N; ++i) print a[i] }
' file
ber,Paris
cho,Paris
dar,Italy
mil,France
ora,usa
plu,Paris

real    0m0.006s
user    0m0.000s
sys     0m0.006s

所以,这取决于您...第一个解决方案是最简单的,并且可以说是最灵活的,因为如果我们想要一个稍微不同的实现(例如,按第二列排序或更改{{ 1}})非常简单,因为管道中两个工具之间的关注点很好地分开了。但是,如果我们担心内存和速度,则可能要考虑最后一个解决方案。

注意:

  • 就其价值而言,我在前两个解决方案中比较了 mawk 1.3.3和 gawk 4.2.1,并且 gawk 始终如一在这种情况下,时间 做梦。)
  • 我还将管道输出定时排到substr(),每个实现相对于彼此的结果是相似的。