Зациклить файл и написать следующую строку, если условие выполняется - PullRequest
2 голосов
/ 25 марта 2010

Трудно исправить это или найти какие-либо хорошие намеки на это. Я пытаюсь перебрать один файл, слегка изменить каждую строку, а затем зациклить другой файл. Если строка во втором файле начинается со строки из первого, то строка , следующая за во втором файле, должна быть записана в третий файл. <pre> with open('ids.txt', 'rU') as f: with open('seqres.txt', 'rU') as g: for id in f: id=id.lower()[0:4]+'_'+id[4] with open(id + '.fasta', 'w') as h: for line in g: if line.startswith('>'+ id): h.write(g.next())

Все правильные файлы появляются, но они пусты. Да, я уверен, что если есть истинные случаи. :-)
"seqres.txt" содержит строки с идентификационным номером в определенном формате, за каждой из которых следует строка с данными. «Ids.txt» содержит строки с интересующими идентификационными номерами в другом формате. Я хочу, чтобы каждая строка данных с интересным идентификационным номером находилась в отдельном файле.

Огромное спасибо всем, кто дал небольшой совет!


Это было минимальное решение, но см. Ответы ниже: <pre> with open('ids.txt', 'rU') as f: fl = f.readlines() with open('seqres.txt', 'rU') as g: gl = g.readlines() for id in fl: id=id.lower()[0:4]+'_'+id[4] with open(id + '.fasta', 'w') as h: for line in xrange(len(gl)): if gl[line].startswith('>'+ id): h.write(gl[line+1])
Теперь мне интересно, есть ли способ сделать это быстрее? См. Ответы Тима и Брайана.

Ответы [ 5 ]

2 голосов
/ 25 марта 2010

Я думаю, что в коде, который вы объявляете финальным, все еще будет достигнут прогресс. Вы можете сделать результат менее вложенным и избежать нескольких глупостей.

from contextlib import nested
from itertools import tee, izip

# Stole pairwise recipe from the itertools documentation
def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

with nested(open('ids.txt', 'rU'), open('seqres.txt', 'rU')) as (f, g):
    for id in f:
        id = id.lower()[0:4] + '_' + id[4]
        with open(id + '.fasta', 'w') as h:
            g.seek(0) # start at the beginning of g each time
            for line, next_line in pairwise(g):
                if line.startswith('>' + id):
                    h.write(next_line)

Это улучшение по сравнению с окончательным кодом, который вы опубликовали в этом

  • Он не излишне считывает файлы целиком в память, а просто перебирает файловые объекты. (Это может или не может быть лучшим вариантом для g, на самом деле. Это определенно лучше масштабируется.)
  • Не содержит условия сбоя с использованием gl[line+1], если мы уже на последней строке gl
    • В зависимости от того, как на самом деле выглядит g, может быть что-то более подходящее, чем pairwise.
  • Это не так глубоко вложено.
  • Он соответствует PEP8 для таких вещей, как пробелы вокруг операторов и глубина отступа.
  • Это алгоритм O (n * m), где n и m - количество строк в f и g. Если длина f не ограничена, вы можете использовать набор ее идентификаторов, чтобы уменьшить алгоритм до O (n) (линейное число строк в g).
2 голосов
/ 25 марта 2010

Вот в основном упрощенная реализация. В зависимости от того, сколько хитов вы получите для каждого идентификатора и сколько записей в «seqres», вы можете изменить его.

# Extract the IDs in the desired format and cache them
ids = [ x.lower()[0:4]+'_'+x[4] for x in open('ids.txt','rU')]
ids = set(ids)

# Create iterator for seqres.txt file and pull the first value
iseqres = iter(open('seqres.txt','rU'))
lineA = iseqres.next()

# iterate through the rest of seqres, staggering
for lineB in iseqres:
  lineID = lineA[1:7]
  if lineID in ids:
    with open("%s.fasta" % lineID, 'a') as h:
      h.write(lineB)
  lineA = lineB
1 голос
/ 25 марта 2010

Для скорости вы действительно хотите избежать многократного зацикливания одного и того же файла. Это означает, что вы превратились в алгоритм O (N * M), когда вы могли бы использовать алгоритм O (N + M).

Чтобы достичь этого, прочтите список идентификаторов в структуре быстрого поиска, например, в виде набора. Поскольку в памяти только 4600, эта форма в памяти не должна быть проблемой.

Новое решение также считывает список в память. Вероятно, это не большая проблема с несколькими сотнями тысяч строк, но она тратит больше памяти, чем нужно, поскольку вы можете сделать все это за один проход, только считывая меньший файл ids.txt в память. Вы можете просто установить флаг, когда предыдущая строка была чем-то интересным, что будет сигнализировать следующую строку, чтобы записать это.

Вот переработанная версия:

with open('ids.txt', 'rU') as f:
    interesting_ids = set('>' + line.lower()[0:4] + "_" + line[4] for line in f)  # Get all ids in a set.

found_id = None
with open('seqres.txt', 'rU') as g:
    for line in g:
        if found_id is not None:
            with open(found_id+'.fasta','w') as h:
                h.write(line)

        id = line[:7]
        if id in interesting_ids: found_id = id
        else: found_id = None
1 голос
/ 25 марта 2010

Проблема в том, что вы циклически просматриваете файл g один раз - после того, как вы прочитали его в первый раз, когда позиция индекса файла остается в конце файла, поэтому дальнейшее чтение завершится неудачно с EOF. Вам нужно будет открывать g каждый раз вокруг цикла.

Однако это будет крайне неэффективно - вы читаете один и тот же файл несколько раз, по одному разу для каждой строки в f. Это будет на порядок быстрее, чтобы прочитать все g в массив в начале и использовать его, пока он будет помещаться в памяти.

0 голосов
/ 25 марта 2010

После обработки первой строки в файле ids.txt файл seqres.txt исчерпан. Что-то не так с вложенностью ваших петель. Кроме того, вы модифицируете итератор внутри цикла for line in g. Не хорошая идея.

Если вы действительно хотите добавить строку, следующую за строкой, идентификатор которой совпадает, то, возможно, что-то подобное может работать лучше:

with open('ids.txt', 'rU') as f:
    ids = f.readlines()
with open('seqres.txt', 'rU') as g:
    seqres = g.readlines()

for id in ids:
    id=id.lower()[0:4]+'_'+id[4]
    with open(id + '.fasta', 'a') as h:
    for line in seqres:
        if line.startswith('>'+ id):
            h.write(seqres.next())
...