0

次の構造のテキスト ファイルを解析しようとしています。

latitude                        5.0000
number_of_data_values             9
  0.1   0.2   0.3   0.4
  1.1   1.2   1.3   1.4      
  8.1
latitude                        4.3000
number_of_data_values             9
  0.1   0.2   0.3   0.4
  1.1   1.2   1.3   1.4       
  8.1
latitude                        4.0000
number_of_data_values             9
  0.1   0.2   0.3   0.4
  1.1   1.2   1.3   1.4       
  8.1
 ...

すべての異なるlatitude数値は、異なる配列行です。 number_of_data_values列の数です (ファイル全体で一貫しています)。

この例では、ファイルを読み取り、次のような 3 x 9 の 2 次元配列を出力します。

array = [[0.1,0.2,0.3,0.4,1.1,1.2,1.3,1.4,8.1],
         [0.1,0.2,0.3,0.4,1.1,1.2,1.3,1.4,8.1],
         [0.1,0.2,0.3,0.4,1.1,1.2,1.3,1.4,8.1]]

ループを使用して行を反復することで試してみましたが、大量の入力ファイルを処理する可能性があるため、より効率的な方法を探しています。

4

2 に答える 2

0

行ごとの実装はかなり簡単で理解しやすいものです。常に新しい行で開始すると仮定するとlatitude(これはあなたの例ではありませんが、タイプミスである可能性があります)、次のことができます。

latitudes = []
counts = []
blocks = []
current_block = []
for line in test:
    print line
    if line.startswith("latitude"):
        # New block: add the previous one to `blocks` and reset
        blocks.append(current_block)
        current_block = []
        latitudes.append(float(line.split()[-1]))
    elif line.startswith("number_of_data"):
        # Just append the current count to the list
        counts.append(int(line.split()[-1]))
    else:
        # Update the current block
        current_block += [float(f) for f in line.strip().split()]
# Make sure to add the last block...
blocks.append(current_block)
# And to remove the first (empty) one
blocks.pop(0)

すべてのブロックが適切なサイズであるかどうかを確認できます。

all(len(b)==c for (c,b) in zip(counts,blocks))

代替ソリューション

ループが心配な場合は、ファイルのメモリ マップ バージョンのクエリを検討することをお勧めします。アイデアは、で始まる行の位置を見つけることlatitudeです。最初の 2 行 ( で始まる行とlatitudeで始まる行number_of_data) を圧縮し、残りの行を結合して処理します。

import mmap

with open("crap.txt", "r+b") as f:
    # Create the mapper
    mapper = mmap.mmap(f.fileno(), 0)
    # Initialize your output variables
    latitudes = []
    blocks = [] 
    # Find the beginning of the first block
    position = mapper.find("latitude")
    # `position` will be -1 if we can't find it
    while (position >= 0):
        # Move to the beginning of the block
        mapper.seek(position)
        # Read the first line
        lat_line = mapper.readline().strip()
        latitudes.append(lat_line.split()[-1])
        # Read the second one
        zap = mapper.readline()
        # Where are we ?
        start = mapper.tell()
        # Where's the next block ?
        position = mapper.find("latitude")
        # Read the lines and combine them into a large string
        current_block = mapper.read(position-start).replace("\n", " ")
        # Transform the string into a list of floats and update the block
        blocks.append(list(float(i) for i in current_block.split() if i))
于 2012-09-01T12:15:28.380 に答える
0

かなり簡単に見えます。数値の解析部分はline.split(). 入力データの形式がどれほど安定しているかに応じて、残りまたは解析を強化または緩和できます。

results = []
latitude = None
numbers_total = None
value_list = []

for line in text.splitlines():
  if line.startswith('latitude '):
    if latitude is not None:
      assert len(value_list) == numbers_total
      results.append((latitude, value_list))
      value_list = []
    latitude = line.split()[-1]
  elif line.startswith('number_of_data_values '):
    numbers_total = int(line.split()[-1])
  else:
    value_list.extend(line.split())

# Make sure the last block gets added to the results.
if latitude is not None:
  assert len(value_list) == numbers_total
  results.append((latitude, value_list))
  value_list = []

for latitude, value_list in results:
  print 'latitude %r: %r' % (latitude, value_list)

これは以下を出力します:

latitude '5.0000': ['0.1', '0.2', '0.3', '0.4', '1.1', '1.2', '1.3', '1.4', '8.1']
latitude '4.3000': ['0.1', '0.2', '0.3', '0.4', '1.1', '1.2', '1.3', '1.4', '8.1']
latitude '4.0000': ['0.1', '0.2', '0.3', '0.4', '1.1', '1.2', '1.3', '1.4', '8.1']
于 2012-09-01T01:04:56.293 に答える