以下是包含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
更喜欢像上面这样简单的单线。
答案 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独立排序。然后你只需要合并相应的行(cut
和paste
)。最后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>