Программа Control-Flow в Python - PullRequest
       10

Программа Control-Flow в Python

1 голос
/ 17 апреля 2009

У меня есть некоторые данные, которые я сохранил в списке, и если я распечатываю список, я вижу следующее:

.
.
.
007 A000000 Y
007 B000000  5
007 C010100  1
007 C020100 ACORN FUND
007 C030100 N
007 C010200  2
007 C020200 ACORN INTERNATIONAL
007 C030200 N
007 C010300  3
007 C020300 ACORN USA
007 C030300 N
007 C010400  4
.
.
.

Точки до и после последовательности должны означать, что есть другие данные, которые аналогично структурированы, но могут или не могут быть частью этого седьмого элемента (007). если первое значение в седьмом элементе - «007 A000000 Y», то я хочу создать словарный список некоторых элементов данных. Я могу сделать это, выполнив все элементы в моем списке и сравнив их значения с некоторыми тестовыми значениями для переменных. Например, строка кода вроде:

if dataLine.find('007 B')==0:
    numberOfSeries=int(dataLine.split()[2])

Что я хочу сделать, так это

if dataLine.find(''007 A000000 Y')==0:
    READ THE NEXT LINE RIGHT HERE

Сейчас мне приходится перебирать весь список для каждого цикла

Я хочу сократить обработку, поскольку у меня есть около 60 КБ файлов, каждый из которых содержит от 500 до 5000 строк.

Я думал о создании еще одной ссылки на список и подсчете данных до тех пор, пока dataLine.find ('' 007 A000000 Y ') == 0. Но, похоже, это не самое элегантное решение.

Ответы [ 5 ]

3 голосов
/ 17 апреля 2009

Вы можете использовать itertools.groupby(), чтобы сегментировать вашу последовательность в несколько подпоследовательностей.

import itertools

for key, subseq in itertools.groupby(tempans, lambda s: s.partition(' ')[0]):
    if key == '007':
    for dataLine in subseq:
        if dataLine.startswith('007 B'):
        numberOfSeries = int(dataLine.split()[2])

itertools.dropwhile() также сработает, если вы действительно просто захотите найти эту строку,

list(itertools.dropwhile(lambda s: s != '007 A000000 Y', tempans))
['007 A000000 Y',
 '007 B000000  5',
 '007 C010100  1',
 '007 C020100 ACORN FUND',
 '007 C030100 N',
 '007 C010200  2',
 '007 C020200 ACORN INTERNATIONAL',
 '007 C030200 N',
 '007 C010300  3',
 '007 C020300 ACORN USA',
 '007 C030300 N',
 '007 C010400  4',
 '.',
 '.',
 '.',
 '']
2 голосов
/ 17 апреля 2009

Единственная сложность использования всех данных в словаре состоит в том, что действительно большой словарь может стать проблематичным. (Это то, что мы привыкли называть «матрицей Биг Оле».)

Решением этой проблемы является создание индекса в Словаре, создание отображения key-> offset с использованием метода tell для получения значения смещения файла. Затем вы можете снова обратиться к строке, выполнив поиск по методу seek.

2 голосов
/ 17 апреля 2009

Вы можете прочитать данные в словарь. Предполагая, что вы читаете из файлового объекта infile:

from collections import defaultdict
data = defaultdict(list)
for line in infile:
    elements = line.strip().split()
    data[elements[0]].append(tuple(elements[1:]))

Теперь, если вы хотите прочитать строку после '007 A000000 Y', вы можете сделать так:

# find the index of ('A000000', 'Y')
idx = data['007'].index(('A000000', 'Y'))
# get the next line
print data['007'][idx+1]
0 голосов
/ 17 апреля 2009

Вы сказали, что хотите сделать это:

if dataLine.find(''007 A000000 Y')==0:
    READ THE NEXT LINE RIGHT HERE

Предположительно, это внутри цикла "for dataLine in data".

В качестве альтернативы, вы можете использовать итератор напрямую, а не в цикле for:

>>> i = iter(data)
>>> while i.next() != '007 A000000 Y': pass  # find your starting line
>>> i.next()  # read the next line
'007 B000000  5'

Вы также упомянули, что у вас есть 60K файлов для обработки. Они все отформатированы одинаково? Они должны быть обработаны по-другому? Если все они могут быть обработаны одинаково, вы можете рассмотреть их объединение в один поток:

def gfind( directory, pattern="*" ):
    for name in fnmatch.filter( os.listdir( directory ), pattern ):
        yield os.path.join( directory, name )

def gopen( names ):
    for name in names:
        yield open(name, 'rb')

def gcat( files ):
    for file in files:
        for line in file:
            yield line

data = gcat( gopen( gfind( 'C:\datafiles', '*.dat' ) ) )

Это позволяет вам лениво обрабатывать все ваши файлы в одном итераторе. Не уверен, поможет ли это вашей текущей ситуации, но я подумал, что стоит упомянуть.

0 голосов
/ 17 апреля 2009

Хорошо, пока я гуглил, чтобы убедиться, что покрыл свои базы, я нашел решение:

Я обнаружил, что забыл думать в списках и словарях, хотя я их использую. Python имеет несколько мощных инструментов для работы с этими типами, чтобы ускорить вашу способность манипулировать ими.
Мне нужен срез, чтобы ссылки на срезы были легко получены с помощью

beginPosit = tempans.index('007 A000000 Y')
endPosit = min([i for i, item in enumerate(tempans) if '008 ' in item])

, где Темпанс является даталистом теперь я могу написать

for line in tempans[beginPosit:endPosit]:
    process each line

Кажется, я ответил на свой вопрос. Я многому научился из других ответов и ценю их, но думаю, это то, что мне было нужно

Хорошо, я собираюсь отредактировать свой ответ. Я многому научился здесь, но кое-что из этого все еще стоит у меня над головой, и я хочу написать немного кода, пока узнаю больше об этом фантастическом инструменте.

from itertools import takewhile
beginPosit = tempans.index('007 A000000 Y')
new=takewhile(lambda x: '007 ' in x, tempans[beginPosit:])

Это основано на более раннем ответе на подобный вопрос и ответ Стивена Хьюга

...