我试图获得每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 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值创建多个文件并在每个文件中查找min来管理它。但我想知道是否可能有更优雅的解决方案呢?
感谢。
答案 0 :(得分:3)
使用Gnu或FreeBSD sort
,您可以按照以下步骤进行操作;
sort -k1,1 -k2,2g file | sort -k1,1g -su
第一个sort
按顺序将文件排序为第一列,然后按第二列值排序。第二个sort
仅使用 第一列来确定文件(-u
)以确定唯一性。它还使用-s
标志来保证第二列仍然有序。在这两种情况下,排序在重要时使用-g
标志(见下文),它执行常规数字比较,不像Posix标准-n
标志只比较前导整数。
效果说明(感谢OP鼓励我进行测量):
在第一种情况下离开g
-k1,1
不是拼写错误;它实际上大大加快了排序(在大文件上,使用Gnu排序)。标准或整数(-n
)排序多比一般数字排序快,可能快10倍。但是,对于“大部分已排序”的文件,所有密钥类型的速度大约是其两倍。对于或多或少均匀采样的随机数,词典排序与一般数字排序非常接近;足够接近,结果显示“大部分已排序”的加速。
可能只能按第一种排序中的第二个字段排序:sort -k2,2g file | sort -k1,1g -su
但这很多更慢,因为第一次传递中的主要排序是通用数字而不是lexicographic,因为文件不再主要为第二次传递排序。
这里只是一个示例点,尽管我做了一些测试,结果相似。输入文件由299,902行组成,每行包含0到1,000,000范围内的两个数字,带有三个十进制数字。第一列中只有100,000个不同的数字;每个出现一到五次,第二列中的数字不同。 (第二列中的所有数字都是不同的,因为它发生了。)
所有时间都是用bash的time
动词收集的,以真实(挂钟)时间为准。 (很好地排序多线程,因此用户时间总是更长)。
第一列正确排序,第二列随机化:
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
答案 1 :(得分:2)
您可以使用此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
答案 2 :(得分: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
}'
答案 3 :(得分:1)
Perl:
def self.months
curr_year = Time.now.year
(1..12).map do |month|
month = "#{ curr_year }-#{ month }-01"
[Date.parse(month).strftime('%Y-%m-%d'), my_select_value]
end
end
它是作为Unix过滤器编写的,因此它从STDIN读取并写入STDOUT。称之为:
#!/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{$_}";
}
答案 4 :(得分:0)
如果要使用排序,首先必须修改排序。排序不会理解小数点,因此临时更改x
现在对数字字段进行数字排序并放回小数点。
生成的列表正确排序,取每个键的第一个值。
sed 's/\./ x /g' inputfile | sort -n -k1,3 -k4,6 | sed 's/ x /./g' | sort -u -k1,1