我们有一些数据,例如:
12 0
13 0
20 0
25 1
64 4
77 1
89 100
1201 204
我想获得这个输出:
3 0
5 1
6 4
7 100
8 204
解释:我们有 3 个度为 0 的 AS(自治系统),然后有 5 个度为 1 或小于 1 的 AS,还有 6 个度为 4 或小于 4 的 AS,并且...
有很多行(100,000)我猜这是分布的 CDF,这是解析 bgpdump 数据的一部分,我想计算这些数字。再次感谢您的帮助
答案1
这是一个简单的 Perl 脚本,可以为您完成这项工作:
#!/usr/bin/perl
use strict;
my %result;
my @data;
my %data;
my @degrees;
my $infile = shift() || die "Usage: $0 <file>\n";
# Read source data from input file
open IN, '<', $infile
or die "Couldn't open data file: $!\n";
while (my $line = <IN>) { chomp $line; push @data, $line; };
close IN;
# Convert data lines to hash
foreach my $line (@data) {
my ($count, $degree) = split(/\s+/, $line);
$data{$degree}++;
};
# Get sorted degrees for count-up iteration
@degrees = sort { $a <=> $b } keys %data;
# Iterate degrees, adding each one's system count to result for this degree
# and all higher degrees
for (my $i = 0; $i < scalar(@degrees); $i++) {
my $degree = $degrees[$i];
my $count = $data{$degree};
for (my $j = $i; $j < scalar(@degrees); $j++) {
$result{$degrees[$j]} += $count;
};
};
# Output result counts
foreach my $degree (sort { $a <=> $b } keys %result) {
print "$result{$degree} $degree\n";
};
对于大型输入数据集,此脚本将需要大量内存;它会在操作之前读取整个输入文件,因为输入文件看起来似乎没有排序,而操作之前需要按度对数据进行排序。也就是说,它应该能很好地完成您的工作 - 如果不行,请告诉我!
答案2
这是一个可以完成这个工作的快速 100% bash 脚本:
a=()
while read _ n; do
[[ -n $n ]] && ((++a[n]))
done < datafile.txt
c=0
for i in ${!a[@]}; do
echo "$((c+=a[i])) $i"
done
如果您想要一个可以从命令行调用的脚本:
#!/bin/bash
a=()
while read _ n; do
[[ -n $n ]] && ((++a[n]))
done < "$1"
c=0
for i in ${!a[@]}; do
echo "$((c+=a[i])) $i"
done
或者如果你想用一句话来打动你的祖母:
a=(); while read _ n; do [[ -n $n ]] && ((++a[n])); done < datafile.txt; c=0; for i in ${!a[@]}; do echo "$((c+=a[i])) $i"; done
它在 2.6GHz 奔腾双核处理器上运行 100000 行文件大约需要 2-3 秒。
编辑
解释:
第一个循环:
- 我们初始化
a
为一个空数组:a=()
- 我们
datafile.txt
逐行读取文件。每行有两个字段,只有第二个字段放在变量名称中n
- 如果
n
非空(这是测试,我们增加数组第个键[[ -n $n ]]
的值;这就是该行的作用。是 bash 的算术上下文。n
a
((++a[n]))
((...))
- 读取完所有文件后,我们得到一个数组
a
,k
第个字段正好是度等于的自治系统的数量k
。
然后是第二个循环:
- 循环之前,变量
c
设置为0。 for i in ${!a[@]}; do
将循环遍历数组的所有键a
。$((c+=a[i]))
将的值添加a[i]
到c
并扩展到该值。该值将与附加到其上的echo
键的值一起进行处理。i
希望这可以帮助!