我想编写一个脚本来处理一些数据文件。数据文件只是带有数据列的ascii文本,这是一个简单的例子......
第一列是ID号,在这种情况下是1到3.第二列是感兴趣的值。 (我正在使用的实际文件有更多的ID和值,但让我们在这里保持简单。)
data.txt内容:
1 5
1 4
1 10
1 19
2 15
2 18
2 20
2 21
3 50
3 52
3 55
3 70
我想迭代数据并提取每个ID的值,并处理它们,即获取ID 1的所有值并对它们执行某些操作,然后获取ID 2的所有值等。
所以我可以在python中写这个。
#!/usr/bin/env python
def processValues(values):
print "Will do something with data here: ", values
f = open('data.txt', 'r')
datalines = f.readlines()
f.close()
currentID = 0
first = True
for line in datalines:
fields = line.split()
# if we've moved onto a new ID,
# then process the values we've collected so far
if (fields[0] != currentID):
# but if this is our first iteration, then
# we just need to initialise our ID variable
if (not first):
processValues(values) # do something useful
currentID = fields[0]
values = []
first = False
values.append(fields[1])
processValues(values) # do something with the last values
我遇到的问题是必须在最后再次调用processValues()
。所以这需要代码重复,这意味着有一天我可能会编写这样的脚本而忘记将额外的processValues()
放在最后,因此错过了最后一个ID。它还需要存储它是否是我们的“第一次”迭代,这很烦人。
无论如何都没有对processValues()
进行两次函数调用(每个新ID都在循环内,最后一个ID循环后有一个)?
我能想到的唯一方法是存储行号并检查循环,如果我们在最后一行。但它似乎消除了我们存储线本身的'foreach'样式处理点,而不是索引或行总数。这也适用于其他脚本语言,例如perl,通常用while(<FILE>)
遍历行并且不知道剩余的行数。是否总是需要在最后再次编写函数调用?
答案 0 :(得分:3)
如果一个键的所有出现都是连续的,你想看看itertools.groupby - 一个基本的例子......
from itertools import groupby
from operator import itemgetter
with open('somefile.txt') as fin:
lines = ( line.split() for line in fin )
for key, values in groupby(lines, itemgetter(0)):
print 'Key', key, 'has values'
for value in values:
print value
或者 - 您也可以使用collections.defaultdict作为默认值list
。
答案 1 :(得分:1)
使用loadtxt()
可能会这样:
from numpy import loadtxt
data = loadtxt("data.txt")
ids = unique(data[:,0]).astype(int)
for id in ids:
d = data[ data[:,0] == id ]
# d is a reduced (matrix) containing data for <id>
# .......
# do some stuff with d
对于您的示例,print d
会给出:
id= 1
d=
[[ 1. 5.]
[ 1. 4.]
[ 1. 10.]
[ 1. 19.]]
id= 2
d=
[[ 2. 15.]
[ 2. 18.]
[ 2. 20.]
[ 2. 21.]]
id= 3
d=
[[ 3. 50.]
[ 3. 52.]
[ 3. 55.]
[ 3. 70.]]