我有一个这样的列表(假设它在summ.txt中存储):
s1 d2
s1 d4
s3 d2
s4 d1
s1 d3
s4 d1
s5 d6
s3 d5
s1 d2
我需要为第一列中的每个元素(s_
)获取第二列(d_
)中的不同元素的数量。在这种情况下:
s1 3
s3 2
s4 1
s5 1
我正在使用shell脚本来获取它:
sor=`cat s.txt`
for d in $sor
do
n=$( grep $d ./summ.txt | cut -f2 | sort -u | wc -l)
echo $d, $n
done
其中s.txt是包含所有不同s_
的文件。在这种情况下,它将是:
s1
s2
s3
s4
s5
我知道这种方法有效,因为我已经尝试过了。主要问题是主列表(summ.txt)由大约19个元素组成,不同s_
的数量大约为3百万,因此计算所有元素需要花费太多时间。你能建议更快的算法吗?
答案 0 :(得分:4)
排序步骤是O( n lg n ),可以避免使用线性时间算法。这是一个Python版本:
distinct_values = defaultdict(set) # hashmap of keys to hashsets of values
for line in sys.stdin:
key, val = line.split()
distinct_values[key].add(val)
for key, values in distinct_values.iteritems():
print key, len(values)
(排序输出可以在O( k lg k )的额外时间获得,其中 k 是不同的数量键。)
答案 1 :(得分:3)
不要为每个s_
浏览一次文件,而是一次完成所有操作:
sort -u | cut -f 1 | uniq -c | awk '{ print $2","$1 }'
应用于您的样本数据,这给出了:
s1,3
s3,2
s4,1
s5,1
此答案中完成的处理与问题中shell脚本中每个s_
的处理大致相同。因此,我预计加速将达到约300万。
答案 2 :(得分:0)
使用DBMS?
或者...
sort <input_file | awk -f counter.awk
#!/usr/bin/awk
// {
if ($1!=prevfirstkey) {
dump();
prevfirstkey=$1;
prevnextkey=$2;
count=1;
} else if ($2 != prevnextkey) {
prevnextkey=$2;
count++;
}
}
dump() {
print prevfirstkey " has " count " values";
count=0;
}
END {
dump();
}