按组排序日期

时间:2014-07-16 14:26:44

标签: bash date awk max min

以下是包含4列和逗号分隔符的数据示例。

1,A,2009-01-01,2009-07-15
1,A,2009-07-10,2009-07-12
2,B,2009-01-01,2009-07-15
2,B,2009-07-10,2010-12-15
3,C,2009-01-01,2009-07-15
3,C,2009-07-15,2010-12-15
3,C,2010-12-15,2014-07-07
4,D,2009-06-01,2009-07-15
4,D,2009-07-21,2012-12-15
5,E,2011-04-23,2012-10-19

前两列已分组。我想要每组的第三列的最小日期和第四列的最大日期。 然后我将为每个前2列组合选择第一行。

期望的输出

1,A,2009-01-01,2009-07-15
2,B,2009-01-01,2010-12-15
3,C,2009-01-01,2014-07-07
4,D,2009-06-01,2012-12-15
5,E,2011-04-23,2012-10-19

我尝试过以下代码,但无法正常工作。我接近了,但不是最大日期。

cat exam |sort -t, -nk1 -k2,3 -k4,4r |sort -t, -uk1,2

更喜欢像上面这样简单的单线。

3 个答案:

答案 0 :(得分:1)

sort datafile |
awk -F, -v OFS=, '
    {key = $1 FS $2} 
    key != prev {prev = key; min[key] = $3} 
    {max[key] = ($4 > max[key]) ? $4 : max[key]} 
    END {for (key in min) print key, min[key], max[key]}
' |
sort
1,A,2009-01-01,2009-07-15
2,B,2009-01-01,2010-12-15
3,C,2009-01-01,2014-07-07
4,D,2009-06-01,2012-12-15
5,E,2011-04-23,2012-10-19

预先排序时,可以保证最小col3日期将出现在新组的第一行。然后你只需要找到最大col4日期。

最后的排序是必需的,因为迭代awk哈希的键是无序的。您可以在(g)awk中执行此排序:

END {
    n = asorti(min, sortedkeys)
    for (i=1; i<=n; i++)
        print sortedkeys[i], min[sortedkeys[i]], max[sortedkeys[i]]
}

答案 1 :(得分:0)

#!/usr/bin/awk -f
BEGIN { FS = OFS = "," }
{
    sub(/[[:blank:]]*<br>$/, "")
    key = $1 FS $2
    if (!a[key]) {
        a[key] = $3
        b[key] = $4
        keys[++k] = key
    } else if ($3 < a[key]) {
        a[key] = $3
    } else if ($4 > b[key]) {
        b[key] = $4
    }
}
END {
    for (i = 1; i <= k; ++i) {
        key = keys[i]
        print key, a[key], b[key] " <br>"
    }
}

用法:

awk -f script.awk file

输出:

1,A,2009-01-01,2009-07-15 <br>
2,B,2009-01-01,2010-12-15 <br>
3,C,2009-01-01,2014-07-07 <br>
4,D,2009-06-01,2012-12-15 <br>
5,E,2011-04-23,2012-10-19 <br>

当然你可以在循环之前和之后添加打印语句来打印其他两个<br>

END {
    print "<br>"
    for (i = 1; i <= k; ++i) {
        key = keys[i]
        print key, a[key], b[key] " <br>"
    }
    print "<br>"
}

答案 2 :(得分:0)

你想要一个“一个班轮”吗?

paste -d, \
 <(cat exam|sort -t, -nk1,2 -k4  |cut -d, -f1-3) \
 <(cat exam|sort -t, -nk1,2 -k4r |cut -d, -f4 ) |
 uniq -w4

关键思想是按字段3 asc对数据进行一次排序,并按字段4 desc独立排序。然后你只需要合并相应的行(cutpaste)。最后uniq用于仅保留每对相同的前两列的第一行。这是这里的弱点,因为我假设4 字符 max用于比较。您必须根据需要进行调整,或以某种方式对这两列的数据进行标准化,以便在使用实际数据时具有固定的宽度。

编辑:可能更好的选择是用简单的uniq过滤器替换awk

paste -d, \
 <(cat exam|sort -t, -nk1,2 -k4  |cut -d, -f1-3) \
 <(cat exam|sort -t, -nk1,2 -k4r |cut -d, -f4 ) |
 awk -F , '$1","$2 != last { print; last=$1","$2 }'

在我的系统(GNU Linux Debian Wheezy)上,两者都产生相同的结果:

1,A,2009-01-01,2009-07-15<br>
2,B,2009-01-01,2010-12-15<br>
3,C,2009-01-01,2014-07-07<br>
4,D,2009-06-01,2012-12-15 <br>
5,E,2011-04-23,2012-10-19<br>