我有一组1000个文本文件,名称为in_s1.txt
,in_s2.txt
等。每个文件包含数百万行,每行有7列,如:
ccc245 1 4 5 5 3 -12.3
对我来说,最重要的是第一列和第七列的值;对ccc245 , -12.3
我需要做的是在所有in_sXXXX.txt
个文件之间找到第7列值最低值的10个案例,并且我还需要获取每个值所在的位置,在哪个文件中。我需要这样的东西:
FILE 1st_col 7th_col
in_s540.txt ccc3456 -9000.5
in_s520.txt ccc488 -723.4
in_s12.txt ccc34 -123.5
in_s344.txt ccc56 -45.6
我正在考虑为此目的使用python和bash,但目前我没有找到实用的方法。我所知道的就是:
in_
IN.TXT
个文件
for i in IN.TXT ; do sort -k6n $i | head -n 10; done
grep -n VALUE in_s*
,因此我为每个值获取文件名它有效,但有点单调乏味。我想知道只使用bash或python或两者的更快的方法。或者另一种更好的语言。
由于
答案 0 :(得分:3)
在python中,使用nsmallest function in the heapq module - 它专为此类任务而设计。
Python 2.5和2.6的示例(已测试):
import heapq, glob
def my_iterable():
for fname in glob.glob("in_s*.txt"):
f = open(fname, "r")
for line in f:
items = line.split()
yield fname, items[0], float(items[6])
f.close()
result = heapq.nsmallest(10, my_iterable(), lambda x: x[2])
print result
接受上述答案后更新
查看Python 2.6的源代码,似乎它有可能list(iterable)
并且可以继续...如果是这样的话,那将无法使用每个包含数百万行的千个文件。如果第一个答案给你MemoryError等,这里有一个替代方法,它将列表的大小限制为n(在你的情况下n == 10)。
注意:仅限2.6;如果您需要2.5,请使用条件heapreplace()
,如文档中所述。使用heappush()
和heappushpop()
没有key
arg :-(所以我们必须伪造它。
import glob
from heapq import heappush, heappushpop
from pprint import pprint as pp
def my_iterable():
for fname in glob.glob("in_s*.txt"):
f = open(fname, "r")
for line in f:
items = line.split()
yield -float(items[6]), fname, items[0]
f.close()
def homegrown_nlargest(n, iterable):
"""Ensures heap never has more than n entries"""
heap = []
for item in iterable:
if len(heap) < n:
heappush(heap, item)
else:
heappushpop(heap, item)
return heap
result = homegrown_nlargest(10, my_iterable())
result = sorted(result, reverse=True)
result = [(fname, fld0, -negfld6) for negfld6, fname, fld0 in result]
pp(result)
答案 1 :(得分:2)
我会:
我不会在这里发布完整的程序,因为它看起来像是家庭作业。
是的,如果不是十,那么这将不是最佳的
答案 2 :(得分:1)
在python中尝试这样的事情:
min_values = []
def add_to_min(file_name, one, seven):
# checks to see if 7th column is a lower value than exiting values
if len(min_values) == 0 or seven < max(min_values)[0]:
# let's remove the biggest value
min_values.sort()
if len(min_values) != 0:
min_values.pop()
# and add the new value tuple
min_values.append((seven, file_name, one))
# loop through all the files
for file_name in os.listdir(<dir>):
f = open(file_name)
for line in file_name.readlines():
columns = line.split()
add_to_min(file_name, columns[0], float(columns[6]))
# print answers
for (seven, file_name, one) in min_values:
print file_name, one, seven
没有测试过,但它应该让你开始。
版本2,只运行一次(在S. Lott的刺激之后):
values = []
# loop through all the files and make a long list of all the rows
for file_name in os.listdir(<dir>):
f = open(file_name)
for line in file_name.readlines():
columns = line.split()
values.append((file_name, columns[0], float(columns[6]))
# sort values, print the 10 smallest
values.sort()
for (seven, file_name, one) in values[:10]
print file_name, one, seven
重新阅读你的问题,有数百万行,你可能会用完RAM ......
答案 3 :(得分:0)
shell解决方案的一个小改进:
$ cat in.txt
in_s1.txt
in_s2.txt
...
$ cat in.txt | while read i
do
cat $i | sed -e "s/^/$i /" # add filename as first column
done |
sort -n -k8 | head -10 | cut -d" " -f1,2,8
答案 4 :(得分:0)
如果您的文件是百万行,您可能需要考虑使用“缓冲”。下面的脚本遍历那些百万行,每次将字段7与缓冲区中的字段进行比较。如果某个值小于缓冲区中的值,则缓冲区中的一个值将替换为新的较低值。
for file in in_*.txt
do
awk -vt=$t 'NR<=10{
c=c+1
val[c]=$7
tag[c]=$1
}
NR>10{
for(o=1;o<=c;o++){
if ( $7 <= val[o] ){
val[o]=$7
tag[o]=$1
break
}
}
}
END{
for(i=1;i<=c;i++){
print val[i], tag[i] | "sort"
}
}' $file
done
答案 5 :(得分:0)
这可能接近你正在寻找的东西:
for file in *; do sort -k6n "$file" | head -n 10 | cut -f1,7 -d " " | sed "s/^/$file /" > "${file}.out"; done
cat *.out | sort -k3n | head -n 10 > final_result.out