3

私はテキスト処理を行っており、次のように「readline()」関数を使用しています:

ifd = open(...)
for line in ifd:
   while (condition)
         do something...
         line = ifd.readline()
         condition = ....

#ここで条件が false になると、'for' ループが同じ行を再度読み取るようにポインターを巻き戻す必要があります。

ifd.fseek() の後に readline を実行すると、'\n' 文字が表示されます。行全体が再度読み取られるようにポインターを巻き戻す方法。

>>> ifd.seek(-1,1)
>>> line = ifd.readline()
>>> line
'\n'

これが私のコードです

labtestnames = sorted(tmp)
#Now read each line in the inFile and write into outFile
ifd = open(inFile, "r")
ofd = open(outFile, "w")
#read the header
header = ifd.readline() #Do nothing with this line. Skip
#Write header into the output file
nl = "mrn\tspecimen_id\tlab_number\tlogin_dt\tfluid"
offset = len(nl.split("\t"))
nl = nl + "\t" + "\t".join(labtestnames)
ofd.write(nl+"\n")
lenFields = len(nl.split("\t"))


print "Reading the input file and converting into modified file for further processing (correlation analysis etc..)"

prevTup = (0,0,0)
rowComplete = 0
k=0
for line in ifd:
    k=k+1
    if (k==200): break

    items = line.rstrip("\n").split("\t")
    if((items[0] =='')):
        continue
    newline= list('' for i in range(lenFields))
    newline[0],newline[1],newline[3],newline[2],newline[4] = items[0], items[1], items[3], items[2], items[4]
    ltests = []
    ltvals = []
    while(cmp(prevTup, (items[0], items[1], items[3])) == 0): # If the same mrn, lab_number and specimen_id then fill the same row. else create a new row.
        ltests.append(items[6])
        ltvals.append(items[7])
        pos = ifd.tell()
        line = ifd.readline()
        prevTup = (items[0], items[1], items[3])
        items = line.rstrip("\n").split("\t")
        rowComplete = 1

    if (rowComplete == 1): #If the row is completed, prepare newline and write into outfile
        indices = [labtestnames.index(x) for x in ltests]
        j=0
        ifd.seek(pos)
        for i in indices:
            newline[i+offset] = ltvals[j]
            j=j+1

    if (rowComplete == 0): # 
        currTup = (items[0], items[1], items[3])
        ltests = items[6]
        ltvals = items[7]
        pos = ifd.tell()
        line = ifd.readline()
        items = line.rstrip("\n").split("\t")
        newTup = (items[0], items[1], items[3])
        if(cmp(currTup, newTup) == 0):
            prevTup = currTup
            ifd.seek(pos)
            continue
        else:
            indices = labtestnames.index(ltests)
            newline[indices+offset] = ltvals

    ofd.write(newline+"\n")
4

2 に答える 2

1

この問題は、 itertools.groupbyを使用してより簡単に処理できます。groupby同じ mrn、標本 ID、および実験番号を扱うすべての連続する行をクラスター化できます。

これを行うコードは

for key, group in IT.groupby(reader, key = mykey):

ここreaderで、入力ファイルの行を反復し、mykeyによって定義されます

def mykey(row):
    return (row['mrn'], row['specimen_id'], row['lab_num'])

からの各行readerが に渡されmykey、同じキーを持つすべての行が同じ にクラスター化されgroupます。


作業中は、 csv モジュールを使用して各行を dict に読み込むこともできます (これを と呼びますrow)。これにより、 のような低レベルの文字列操作に対処する必要がline.rstrip("\n").split("\t")なくなり、インデックス番号 ( など) で列を参照する代わりに、row[3]などの高レベルの用語で話すコードを書くことができますrow['lab_num']


import itertools as IT
import csv

inFile = 'curious.dat'
outFile = 'curious.out'

def mykey(row):
    return (row['mrn'], row['specimen_id'], row['lab_num'])

fieldnames = 'mrn specimen_id date    lab_num Bilirubin   Lipase  Calcium Magnesium   Phosphate'.split()

with open(inFile, 'rb') as ifd:
    reader = csv.DictReader(ifd, delimiter = '\t')
    with open(outFile, 'wb') as ofd:
        writer = csv.DictWriter(
            ofd, fieldnames, delimiter = '\t', lineterminator = '\n', )
        writer.writeheader()
        for key, group in IT.groupby(reader, key = mykey):
            new = {}
            row = next(group)
            for key in ('mrn', 'specimen_id', 'date', 'lab_num'):
                new[key] = row[key]
                new[row['labtest']] = row['result_val']                
            for row in group:
                new[row['labtest']] = row['result_val']
            writer.writerow(new)

収量

mrn specimen_id date    lab_num Bilirubin   Lipase  Calcium Magnesium   Phosphate
4419529 1614487 26.2675 5802791G    0.1             
3319529 1614487 26.2675 5802791G    0.3 153 8.1 2.1 4
5713871 682571  56.0779 9732266E                    4.1
于 2012-11-20T16:33:01.600 に答える
0

これは、 yield 式の完璧な使用例のようです。ファイルから行を出力し、それらのいくつかをランダムに繰り返す次の例を考えてみましょう:

def buflines(fp):
    r = None
    while True:
        r = yield r or next(fp)
        if r:
            yield None

from random import randint

with open('filename') as fp:
    buf = buflines(fp)
    for line in buf:
        print line
        if randint(1, 100) > 80:
            print 'ONCE AGAIN::'
            buf.send(line)

基本的に、アイテムをもう一度処理したい場合はsend、ジェネレーターに戻ります。次の反復では、同じアイテムをもう一度読み取ることになります。

于 2012-11-20T17:18:22.093 に答える