Awk 在与另一列对应的列中查找最大值和最小值

Awk 在与另一列对应的列中查找最大值和最小值,awk,Awk,我有一个5列、10000多行的CSV数据文件。我需要从第2列中为第1列中的每个不同值找到最大值和最小值,然后将它们写入新文件。我对grep、awk、head、tail和其他类似的人都是比较陌生的。这里有几行文件,我们可以称之为temp.csv 1553 1806.345000 20130516-044310 33.800000 -97.110000 1555 2106.947000 20130516-044310 33.470000 -94.620000 1559 2106.947000

我有一个5列、10000多行的CSV数据文件。我需要从第2列中为第1列中的每个不同值找到最大值和最小值,然后将它们写入新文件。我对grep、awk、head、tail和其他类似的人都是比较陌生的。这里有几行文件,我们可以称之为temp.csv

1553 1806.345000 20130516-044310 33.800000 -97.110000 

1555 2106.947000 20130516-044310 33.470000 -94.620000

1559 2106.947000 20130516-044310 31.460000 -97.260000

1573 1807.591000 20130516-045311 41.150000 -94.020000

1573 2107.911000 20130516-045311 41.120000 -94.020000

1573 2408.994000 20130516-045311 41.120000 -94.050000

1573 2709.545000 20130516-045311 41.090000 -94.020000

1573 3010.308000 20130516-045311 41.090000 -94.020000

1573 3310.988000 20130516-045311 41.090000 -93.990000

1573 3611.129000 20130516-045311 41.120000 -93.960000

1573 3912.392000 20130516-045311 41.090000 -93.960000

1585 1806.756000 20130516-045812 31.040000 -98.880000

1585 2107.839000 20130516-045812 31.040000 -98.850000

1585 2408.390000 20130516-045812 31.010000 -98.820000

1585 2709.153000 20130516-045812 31.010000 -98.790000

1611 1804.813000 20130516-051316 31.280000 -97.800000
例如,从这些数据中,我希望输出如下所示:

1553 1806.345000 20130516-044310 33.800000 -97.110000 

1555 2106.947000 20130516-044310 33.470000 -94.620000

1559 2106.947000 20130516-044310 31.460000 -97.260000

1573 1807.591000 20130516-045311 41.150000 -94.020000

1573 3912.392000 20130516-045311 41.090000 -93.960000

1585 1806.756000 20130516-045812 31.040000 -98.880000

1585 2709.153000 20130516-045812 31.010000 -98.790000

1611 1804.813000 20130516-051316 31.280000 -97.800000

第一行中的一些数字只有一个条目,其中显然是最大和最小的。任何帮助都将不胜感激。

以下是完成任务的一种方法。不管数据是否排序:

awk '  
$1 in keys {
    map["min",$1] = (keys[$1] < $2 ? map["min",$1] : $0); 
    map["max",$1] = (keys[$1] > $2 ? map["max",$1] : $0);
}
NF {
    keys[$1] = $2;
}
!seen[$1]++ {
    map["min",$1] = $0;
    map["max",$1] = $0;
}
END {
    for (key in keys) {
        if (map["min",key] == map["max",key]) {
            print map["min",key]
        }
        else { 
            print map["min",key]
            print map["max",key]
        }
    }
}' file
1611 1804.813000 20130516-051316 31.280000 -97.800000
1585 1806.756000 20130516-045812 31.040000 -98.880000
1585 2709.153000 20130516-045812 31.010000 -98.790000
1553 1806.345000 20130516-044310 33.800000 -97.110000 
1555 2106.947000 20130516-044310 33.470000 -94.620000
1559 2106.947000 20130516-044310 31.460000 -97.260000
1573 1807.591000 20130516-045311 41.150000 -94.020000
1573 3912.392000 20130516-045311 41.090000 -93.960000
awk'
钥匙1美元{
地图[“分钟”,“1美元]=(按键[$1]<$2?地图[“分钟”,“1美元]:$0);
map[“max”,$1]=(键[$1]>$2?map[“max”,$1]:$0);
}
核因子{
按键[$1]=$2;
}
!见[$1]++{
地图[“分钟”,$1]=$0;
地图[“最大值”,$1]=$0;
}
结束{
用于(输入键){
如果(映射[“最小”,键]==映射[“最大”,键]){
打印地图[“最小”,键]
}
否则{
打印地图[“最小”,键]
打印地图[“最大”,键]
}
}
}"档案"
1611 1804.813000 20130516-051316 31.280000 -97.800000
1585 1806.756000 20130516-045812 31.040000 -98.880000
1585 2709.153000 20130516-045812 31.010000 -98.790000
1553 1806.345000 20130516-044310 33.800000 -97.110000 
1555 2106.947000 20130516-044310 33.470000 -94.620000
1559 2106.947000 20130516-044310 31.460000 -97.260000
1573 1807.591000 20130516-045311 41.150000 -94.020000
1573 3912.392000 20130516-045311 41.090000 -93.960000
输出:

1553 1806.345000 20130516-044310 33.800000 -97.110000 
1555 2106.947000 20130516-044310 33.470000 -94.620000
1559 2106.947000 20130516-044310 31.460000 -97.260000
1573 1807.591000 20130516-045311 41.150000 -94.020000
1573 3912.392000 20130516-045311 41.090000 -93.960000
1585 1806.756000 20130516-045812 31.040000 -98.880000
1585 2709.153000 20130516-045812 31.010000 -98.790000
1611 1804.813000 20130516-051316 31.280000 -97.800000

复制品呢?保留第一个或最后一个最小/最大值?是的,只需要一个。谢谢您输入的每个数据行之间真的有空行吗?不,请忽略空白行,谢谢您的KONSOLBOX,您介意解释一下代码吗?它工作得很好,我想了解它在做什么来学习it@user2938093该解决方案基于对行进行排序的假设。每个块
x{}
将针对除了
END
之外找到的每个记录(行)运行<代码>!如果字段数为0,NF{next}将跳过它后面的块。它发生在空行中<代码>!如果第一次遇到第一列中的值,[$1]+将给出true条件,并允许执行
{if(length(p))print p;print;p=“”;next}
。该块的用途是打印上一个辅助值(如果有),打印当前行,将
p
重置为空并跳过下一个块。当所有条件(
!NF
!a[$1]+
)都为false时,
{p=$0}
将执行。这将为第一列中的当前值设置要打印的第二行。它将继续赋值,直到第一列上的下一个新值(即,
!a[$1]+
再次计算为true)或直到到达文件末尾,在那里也将执行
end
块,+1美观、清晰、简单、健壮。。。我可能得退休了:-)。等一下。键[$1]只包含给定$1的第一个值,因此只有当输入按$2为每$1排序时,这才有效。如果$2的值先是15,然后是5,然后是10,那么“min”值将用于带10的行,而不是带5的行。您需要单独的最小和最大数组,而不是单个键数组。或者只是声明它要求每个$1的输入按$2排序。至少它不需要对$1的值进行排序,也不需要连续。@EdMorton,这就是我说我仍然需要从你那里学到很多东西的意思。包括一个用于修复该问题的块。非常感谢您的反馈。你是最棒的<代码>:)
1553 1806.345000 20130516-044310 33.800000 -97.110000 
1555 2106.947000 20130516-044310 33.470000 -94.620000
1559 2106.947000 20130516-044310 31.460000 -97.260000
1573 1807.591000 20130516-045311 41.150000 -94.020000
1573 3912.392000 20130516-045311 41.090000 -93.960000
1585 1806.756000 20130516-045812 31.040000 -98.880000
1585 2709.153000 20130516-045812 31.010000 -98.790000
1611 1804.813000 20130516-051316 31.280000 -97.800000