如何在python中没有代码重复的情况下迭代数据文件?

时间:2012-11-30 12:18:53

标签: python code-duplication

我想编写一个脚本来处理一些数据文件。数据文件只是带有数据列的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>)遍历行并且不知道剩余的行数。是否总是需要在最后再次编写函数调用?

2 个答案:

答案 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.]]