2016-05-21 3 views
1

Python 3.5で具体的にフォーマットされたファイル(Butcher tableau)を読み込もうとしています。 ファイルこの(タブ区切り)のようになります。例えばファイルからButcherテーブルを読み取るためのエレガントで読みやすい方法

S 
a1 b11 b12 ... b1S 
a2 b21 b22 ... b2S 
... 
aS bS1 bS2 ... bSS 
0.0 c1 c2 ... cS 
[tolerance] 

、(タブ区切り)

2 
0.0 0.0 0.0 
1.0 0.5 0.5 
0.0 0.5 0.5 
0.0001 

私はCで書いているようなので、私のコードは見た目よりニシキヘビのアプローチがありますこのファイルを解析するには?おそらく、ここで使用できるnumpyメソッドがありますか?

#the data from .dat file 
S = 0 #method order, first char in .dat file 
a = [] #S-dim left column of buther tableau 
b = [] #S-dim matrix 
c = [] #S-dim lower row 
tolerance = 0 # for implicit methods 

def parse_method(file_name): 
    'read the file_name, process lines, produce a Method object' 
    try: 
     with open('methods\\' + file_name) as file: 
      global S 
      S = int(next(file)) 
      temp = [] 
      for line in file: 
       temp.append([float(x) for x in line.replace('\n', '').split('\t')]) 
     for i in range(S): 
      a.append(temp[i].pop(0)) 
      b.append(temp[i]) 
     global c 
     c = temp[S][1:] 
     global tolerance 
     tolerance = temp[-1][0] if len(temp)>S+1 else 0 
    except OSError as ioerror: 
     print('File Error: ' + str(ioerror)) 
+0

実際のファイルを実際の値で記述することはできますか?理解しやすくなります。 –

+0

あなたが正しいです、私は例を追加しました –

+0

Ok。私は答えを追加します。 –

答えて

1

私の提案numpyの使用:私はnumpy.fromfileは、ファイルポインタを進め、どのように一貫して完全にはよく分からないが、

import numpy as np 

def read_butcher(filename): 
    with open(filename, 'rb') as fh: 
     S = int(fh.readline()) 
     array = np.fromfile(fh, float, (S+1)**2, '\t') 
     rest = fh.read().strip() 

    array.shape = (S+1, S+1) 
    a = array[:-1, 0] 
    b = array[:-1, 1:] 
    c = array[ -1, 1:] 
    tolerance = float(rest) if rest else 0.0 

    return a, b, c, tolerance 

を..ドキュメンテーションには保証はありません。

ファイル例外の処理は、おそらく解析メソッド外で行う必要があります。

+0

実際には、これはより簡潔で読みやすいものですから、私は答えとして投票します。しかし、numpy.fromfile()の第4引数は唯一のものです。 '' \ t ''でなければ' b'でなければなりません。そうでなければ例外をスローします。 –

+0

@Nick - 私はそこで賢明にしようとしました。 ''\ t''はPython 2とPython 3の両方で動作するはずです。 –

0

ここでは、検討すべき提案の束です:

from collections import namedtuple 
import csv 

def parse_method(file_name): 
    # for conveniency create a namedtuple 
    bt = namedtuple('ButcherTableau', dict(a=[], b=[], c=[], order=0, tolerance=0)) 

    line = None 

    # advice ①: do not assume file path in a function, make assumptions as close to your main function as possible (to make it easier to parameterize later on) 
    # advice ②: do not call your file "file" so you're not shadowing the class "file" that's loaded globally at runtime 
    with open(file_name, 'r') as f: 
     # read the first line alone to setup your "method order" value before reading all the tab separated values 
     bt.order = int(f.readline()) 

     # create a csv reader with cell separator as tabs 
     # and create an enumerator to have indexes for each line 
     for idx, line in enumerate(csv.reader(f, delimiter='\t'))) 

      # instead of iterating again, you can just check the index 
      # and build your a and b values 
      if idx < bt.order: 
       bt.a.append(line.pop(0)) 
       bt.b.append(line) 

     # if line is None (as set before the for), it means we did not iterate, meaning that we need to make it an error 
     if not line: 
      raise Exception("File is empty. Could not parse {}".format(file_name)) 

     # finally you can build your c (and tolerance) values with the last line, which conveniently is still available once the for is finished 
     bt.c = line[1:] 
     bt.tolerance = line[0] if idx > S+1 else 0 

    # avoid the globals, return the namedtuple instead and use the results in the caller function 
    return bt 

このコードは(私はそれを読むと、単にあなたのコードの手直し)テストされていないので、それがそのまま動作しない場合がありますが、あなたは可能性があります良いアイデアを取って自分のものにしたい。

1

コード -

from collections import namedtuple 


def parse_file(file_name): 
    with open('a.txt', 'r') as f: 
     file_content = f.readlines() 
    file_content = [line.strip('\n') for line in file_content] 
    s = int(file_content[0]) 
    a = [float(file_content[i].split()[0]) for i in range(1, s + 1)] 
    b = [list(map(float, file_content[i].split()[1:])) 
     for i in range(1, s + 1)] 
    c = list(map(float, file_content[-2].split())) 
    tolerance = float(file_content[-1]) 
    ButcherTableau = namedtuple('ButcherTableau', 's a b c tolerance') 
    bt = ButcherTableau(s, a, b, c, tolerance) 
    return bt 

p = parse_file('a.txt') 

print('S :', p.s) 
print('a :', p.a) 
print('b :', p.b) 
print('c :', p.c) 
print('tolerance :', p.tolerance) 

出力 -

S : 2 
a : [0.0, 1.0] 
b : [[0.0, 0.0], [0.5, 0.5]] 
c : [0.0, 0.5, 0.5] 
tolerance : 0.0001 
+0

ありがとうございます、それは実際にはもっとpythonicです。私の唯一の懸念は、私が聞いた「地図」の使用が落胆していることです。しかし、ここではリスト内包よりも適切だと思われます –

+0

同じ関数をリストに適用する場合は、マップは絶対に問題ありません。しかし、異なる人々は異なる好みを持っている。 –

関連する問題