如何根据另一列中的最早日期为每个 ID 仅选择一条记录?

如何根据另一列中的最早日期为每个 ID 仅选择一条记录?

我有一个包含多行的文件,其中的字段由标签:

ID Code Date
1  XX   23/1/2018
1  XX   11/3/2021
2  XX   14/5/2011
2  XX   20/9/2013
3  XX   08/7/2014
3  XX   11/9/2016
3  XX   27/10/2018

我想ID根据列中最早日期的条目为每个参与者保留一个条目Date。对于每个参与者,日期按从最早到最新的顺序排列。

我想要的输出是:

1  XX   23/1/2018
2  XX   14/5/2011
3  XX   08/7/2014

答案1

由于您声明每个参与者的记录是按从最旧到最新的顺序排列的,并且您只想打印每个参与者的最早日期的记录ID,因此这相当于打印每个新的遇到的第一行ID。使用以下方法可以轻松实现这一点awk

awk -F'\t' 'FNR>1 && !seen[$1]++' input.txt

这将首先将字段分隔符设置为\t。然后,它会评估之间的条件' ... '来决定是否打印当前行。如果出现以下情况,将会打印一行

  • 每个文件的行计数器大于一(为了跳过标题行),
  • 该数组seen尚不包含第一列 ( $1) 的当前值的条目。这是有效的,因为取消引用尚未分配的数组值的计算结果为false。此外,后缀运算符++仅在该评估之后应用,因此对于特定的第一次遇到,ID此返回 true,但对于任何以后的遇到,其中seen[$1]大于 0,它将返回false并从而禁止打印该行。

如果你想保留标题行,只需删除FNR>1条件:

awk -F'\t' '!seen[$1]++' input.txt

(它将被打印,因为ID这一行的字面上地 ID,当然还有该特定值的第一次出现。)

答案2

以下用途磨坊主mlr,一种处理结构化数据的工具)来解析 TSV 文件中的记录。它按ID值和输出对记录进行分组首先在每组中发现价值:

$ mlr --tsv head -g ID -n 1 file
ID      Code    Date
1       XX      23/1/2018
2       XX      14/5/2011
3       XX      08/7/2014

如果日期是不是对每个进行排序ID,我们可以通过将每个日期字符串转换为 Unix 时间戳并在这个新字段上进行数字排序来对它们进行排序。排序后,我们进行与上面相同的操作,然后对剪切(删除)时间戳字段后的值head重新排序。ID

mlr --tsv \
    put '$ts = strptime($Date, "%d/%m/%Y")' then \
    sort -n ts then \
    head -g ID -n 1 then \
    cut -x -f ts then \
    sort -n ID file

输出与问题中所示的示例相同。

答案3

您可以使用以下代码获得所需的输出:

sed 1d file_of_data | sort -k1,2n -u

这样做的作用是,

  1. 用于sed丢弃(删除)包含标题的第一行
  2. sort结果文件按第一列数字排列,丢弃(该排序字段的)重复项

输出

1  XX   23/1/2018
2  XX   14/5/2011
3  XX   08/7/2014

相关内容