Bash 为每个唯一的$1查找最小的$2
我试图为每1美元的价值获得最小的2美元价值。我的数据如下所示:Bash 为每个唯一的$1查找最小的$2,bash,perl,awk,sed,Bash,Perl,Awk,Sed,我试图为每1美元的价值获得最小的2美元价值。我的数据如下所示: 0 0 23.9901 13.604 23.9901 13.604 23.9901 3.364 23.9901 3.364 24.054 18.5279 25.0981 17.4839 42.582 0 45.79 0 45.79 15.36 45.7902 12.1518 51.034 12.028 54.11 14.072 54.1102 14.0718 输出必须如下所示: 0 0 23.9901 3.364 24.054 1
0 0
23.9901 13.604
23.9901 13.604
23.9901 3.364
23.9901 3.364
24.054 18.5279
25.0981 17.4839
42.582 0
45.79 0
45.79 15.36
45.7902 12.1518
51.034 12.028
54.11 14.072
54.1102 14.0718
输出必须如下所示:
0 0
23.9901 3.364
24.054 18.5279
25.0981 17.4839
42.582 0
45.79 0
45.7902 12.1518
51.034 12.028
54.11 14.072
54.1102 14.0718
我可以通过为每个$1值创建多个文件并在每个文件中查找最小值来管理此操作。但我想知道是否有更优雅的解决方案
谢谢。您可以这样做:
awk 'NR==1{k=$1;v=$2;next} k==$1 { if (v>$2) v=$2; next} {print k,v; k=$1;v=$2}END{print k,v}'
缩进:
# for the first record store the two fields
NR==1 {
k=$1
v=$2
next
}
# when the first field doesn\'t change
k==$1 {
# check if the second field is lower
if (v>$2)
v=$2
next
}
{
# otherwise print stored fields and reinitialize them
print k,v
k=$1
v=$2
}
END {
print k,v
}'
您可以使用以下gnu awk命令:
awk '!($1 in m) || m[$1]>$2{m[$1]=$2} END{for (i in m) print i, m[i]}' file
或获取与输入文件相同的顺序:
awk 'BEGIN{PROCINFO["sorted_in"]="@ind_num_asc"} !($1 in m) || m[$1] > $2 {m[$1] = $2}
END{for (i in m) print i, m[i]}' file
BEGIN{PROCINFO[“sorted_in”]=“@ind_num_asc”}
用于按数字索引对关联数组进行排序
输出:
0 0
23.9901 3.364
24.054 18.5279
25.0981 17.4839
42.582 0
45.79 0
45.7902 12.1518
51.034 12.028
54.11 14.072
54.1102 14.0718
在Perl中:
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
my %min;
while (<>) {
chomp;
my ($key, $value) = split;
if (!exists $min{$key} or $value < $min{$key}) {
$min{$key} = $value;
}
}
for (sort { $a <=> $b } keys %min) {
say "$_ $min{$_}";
}
#/usr/bin/perl
严格使用;
使用警告;
使用5.010;
我的%min;
而(){
咀嚼;
我的($key,$value)=分割;
如果(!存在$min{$key}或$value<$min{$key}){
$min{$key}=$value;
}
}
对于(排序{$a$b}键%min){
说“$\$min{$\}”;
}
它是作为Unix筛选器编写的,因此它从STDIN读取并写入STDOUT。称之为:
$ ./get_min < input_file > output_file
$./get\u minoutput\u file
使用Gnu或FreeBSD排序
,您可以按如下操作:
sort -k1,1 -k2,2g file | sort -k1,1g -su
第一个sort
按第一列和第二列值对文件进行排序。第二个排序
仅使用第一列来确定唯一性,从而对文件(-u
)进行唯一性验证。它还使用-s
标志来确保第二列仍处于有序状态。在这两种情况下,排序在重要时使用-g
标志(见下文),该标志进行一般数字比较,而Posix标准-n
标志仅比较前导整数
性能说明:(感谢OP鼓励我进行测量):
将-k1,1
中的g
保留在第一个排序中不是打字错误;它实际上大大加快了排序速度(对于大文件,使用Gnu排序)。标准或整数(-n
)排序比普通数字排序快得多,可能快10倍。但是,对于“大部分已排序”的文件,所有键类型的速度大约是其两倍。对于或多或少均匀抽样的随机数,字典排序与一般数字排序非常接近;足够接近,结果显示“大部分排序”的加速
在第一次排序中,可以只按第二个字段进行排序:sort-k2,2g file | sort-k1,1g-su
,但这要慢得多,这是因为第一次排序中的主要排序是普通数字而不是字典,而且第二次排序时文件不再主要排序
这里只有一个示例点,尽管我做了一些测试,结果类似。输入文件由299902行组成,每行包含两个0到1000000范围内的数字,以及三个十进制数字。第一列中正好有100000个不同的数字;每一个在第二列中以不同的数字显示一到五次。(第二列中的所有数字都是不同的。)
所有计时都是用bash的time
verb收集的,以实际(wallclock)时间为准。(很好地对多线程进行排序,这样用户时间总是更长)
第一列正确排序,第二列随机化:
sort -k1,1 -k2,2g sorted | sort -k1,1g -su 1.24s
sort -k1,1g -k2,2g sorted | sort -k1,1g -su 1.78s
sort -k2,2g sorted | sort -k1,1g -su 3.00s
sort -k1,1 -k2,2g unsorted | sort -k1,1g -su 1.42s
sort -k1,1g -k2,2g unsorted | sort -k1,1g -su 2.19s
sort -k2,2g unsorted | sort -k1,1g -su 3.01s
将第一列随机分组:
sort -k1,1 -k2,2g sorted | sort -k1,1g -su 1.24s
sort -k1,1g -k2,2g sorted | sort -k1,1g -su 1.78s
sort -k2,2g sorted | sort -k1,1g -su 3.00s
sort -k1,1 -k2,2g unsorted | sort -k1,1g -su 1.42s
sort -k1,1g -k2,2g unsorted | sort -k1,1g -su 2.19s
sort -k2,2g unsorted | sort -k1,1g -su 3.01s
当您想使用sort时,首先必须修复排序。排序将不理解小数点,因此临时更改为a
x
现在对数值字段中的数值进行排序,并将小数点放回原处。 结果列表排序正确,取每个键的第一个值
sed 's/\./ x /g' inputfile | sort -n -k1,3 -k4,6 | sed 's/ x /./g' | sort -u -k1,1
23.9901的最小值为3.364。相同的$1值是否总是连续的?是的,这是正确的。刚刚修好了$1值总是递增排序。此外,您的示例输出看起来已将
$1
四舍五入到小数点后两位,您的输出中只有45.79 0
,是否要进行ot处理45.7902 12.1518
。陛下否您在54.1102 14.0718
中包含了类似的案例。哦,是的,你忘了在代码中包含你解决问题的尝试。我们可以帮助您修复代码,但S.O.不是免费的编码服务。祝你好运。这是解决这个问题的好方法!但是,对于大数据来说有点慢…@jamie:是的,这种解决方案更适合于第一列尚未排序的情况。我在说明书中遗漏了这一点。