python iterate выбирает только строку, содержащую определенный символ

#python #list #character

#python #Список #символ

Вопрос:

Я хочу выполнить итерацию по списку kmers, и выбранные элементы содержат только символы A, T, G и C

 kmers=["AL","AT","GC","AA","AP"]

for kmer in kmers:       
    for letter in kmer:
        if letter not in ["A","T","G","C"]:
            pass
        else:
            DNA_kmers.append(kmer)
            print("DNA_kmers",DNA_kmers)
  

вывод:

 DNA_kmers ['AL', 'AT', 'AT', 'GC', 'GC', 'AA', 'AA', 'AP']
  

желаемый результат:

 DNA_kmers=["AT","GC","AA"]
  

Единственный метод, который я знаю, это

 if "B" in kmer or "D" in kmer or "E" in kmer or "F" in kmer or "H" in kmer or "I" in kmer or "J" in kmer or "K" in kmer or "L" in kmer or "M" in kmer or "N" in kmer or "O" in kmer or "P" in kmer or "Q" in kmer or "R" in kmer or "S" in kmer or "U" in kmer or "V" in kmer or "W" in kmer or "X" in kmer or "Y" in kmer or "Z" in kmer:
   pass
  

Комментарии:

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

2. @ggorlen Спасибо. Я новичок в python, работаю над практическим файлом с размером файла около 400 тыс. Kmer будет небольшим списком для практики.

Ответ №1:

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

 kmers=["AL","AT","GC","AA","AP"]
DNA_kmers =[]

for kmer in kmers:       
    for letter in kmer:
        if letter not in ["A","T","G","C"]:
            break
    else:
        DNA_kmers.append(kmer)

print("DNA_kmers",DNA_kmers)
  

Если вы не знакомы с Python, я использовал else предложение в for цикле. Это доступно не на всех языках. else Блок будет запущен тогда и только тогда, когда цикл завершит все итерации.

Существуют значительно более простые способы сделать то, что вы пытаетесь сделать. Например, следующее выполнит работу, используя понимание вложенного списка:

 kmers=["AL","AT","GC","AA","AP"]

allowed = set("AGCT")
print([k for k in kmers if all([c in allowed for c in k])])
  

Более производительным решением общего назначения является использование регулярных выражений:

 import re

kmers=["AL","AT","GC","AA","AP"]
r = re.compile("^[ATGC]*$")
print([k for k in kmers if r.match(k)])
  

Если мы ограничим проблему только k-мер, где k = 2, мы сможем дополнительно оптимизировать производительность. Производительность регулярных выражений должна немного увеличиться при сопоставлении строки фиксированной длины, например, с помощью [AGCT]{2} . Мы также можем использовать product для создания набора, который будет использоваться для поиска в постоянное время:

 import itertools

kmers=["AL","AT","GC","AA","AP"]

allowed = {a b for a,b in itertools.product("AGCT", repeat=2)}
print([k for k in kmers if k in allowed])
  

Комментарии:

1. @ggorlen Я не уверен, перераспределяется ли он каждый раз или нет, но я обновил свой ответ, чтобы вытащить инициализацию. Похоже, это примерно в 2 раза быстрее: repl.it/@jncraton/ImmaterialPassionateIrc#main.py

2. Да, но all до сих пор нет раннего спасения, поэтому, если k длина 100000, а первого символа нет allowed , вы действительно хотите сразу остановиться. Смотрите Мой ответ для правильной версии. Как я уже упоминал, предостережение заключается в том, что если длина строки всегда равна 2, накладные расходы генератора на распределение могут сделать его медленнее, чем LC. Я попросил OP уточнить.

3. @ggorlen Верно. Похоже, что этот re метод является самым быстрым из этих решений. Выражение компилируется до чего-то эффективного, включающего раннее спасение, которое вы описываете.

4. Причина re , по которой версия быстра для коротких строк, заключается в том, что она имеет наименьшие накладные расходы на выделение объектов в цикле относительно LC и generator, и это узкое место.

5. @ggorlen Это кажется правильным. Я добавил версию, которая использует поиск по набору, и она самая быстрая.