计算大型列表中的不同元素太慢

时间:2011-12-06 12:19:02

标签: shell comparison time-complexity

我有一个这样的列表(假设它在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百万,因此计算所有元素需要花费太多时间。你能建议更快的算法吗?

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();
}