LINUX.ORG.RU

Лишние итерации в программе

 


0

3

Всем привет. Есть функция внутри программы, которая проверяет формат строки на предмет ненужных символов. Если выделить в отедльный скрипт

import string

spisok_star = list(...)
spisok_nov = []
simvoli = string.ascii_letters + string.digits + string.punctuation + string.whitespace

for ludi in spisok:
    for b in ludi:
        if b in simvoli:
            spisok_nov.append(ludi)
            
Список этот содержит элементы вида «Имя Фамилия Дата Рождения» (из файла выдернуто). Трабла в том, что таким образом все прошедшие проверку на символы элементы списка в новом списке повторяются столько раз, сколько символов в элементе. Это из за итерации при проверки на вхождение. Так каким образом это можно исправить, чтобы изначально запись в новый список производилась 1 раз? Не форматируя список лишний раз всякими множествами и т.д.



Последнее исправление: Nasvay28 (всего исправлений: 1)

Разделить проход по символам для проверки и добавление в результирующий список?

А вообще почитай что-нибудь по декомпозиции - SICP для начала.

Begemoth ★★★★★
()
Ответ на: комментарий от aureliano15

Если я вынесу добавление в предыдущий цикл, как мне тогда организовать действие по последнему условию вхождения нужных символов?

Nasvay28
() автор топика
Ответ на: комментарий от Nasvay28

Раздели проверку наличия нужных/ненужных символов и следующее за этим действие.

Begemoth ★★★★★
()

Еще раз, ребят. Я знаю, что это все можно сделать отдельно, вне этих циклов, но тогда и код деоптимизируется. Придется лишний раз хранить список, который будет переформировываться и брать ресурсы. Если не найду вариантов, я конечно так и сделаю, но если есть типс'энд'трикс для этого, рад буду узнать.

Nasvay28
() автор топика
Ответ на: комментарий от Nasvay28

Какая нафиг оптимизация, если ты алгоритм сформулировать не можешь? И с чего ты решил, что оптимизация нужна?

Begemoth ★★★★★
()
Ответ на: комментарий от Nasvay28

Придется лишний раз хранить список, который будет переформировываться и брать ресурсы

Вообще-то разделение логики на функции никак не навязывает использование дополнительных списков

Begemoth ★★★★★
()
Ответ на: комментарий от Begemoth

Потому и обратился, что не могу сообразить. А оптимизация нужна, потому что списки, с которыми работаю, по несколько миллионов строк. И функция далеко не единственная в программе. Чем быстрее работает, тем лучше.

Nasvay28
() автор топика

Как-то так попробуй.

def verify(name):
    for c in name:
        if c not in simvoli:
            return False
    return True

for ludi in spisok:
    verified = True
    for name in ludi:
        verified &= verify(name)
    if verified:
        spisok_nov.append(ludi)
hippi90 ★★★★★
()
Последнее исправление: hippi90 (всего исправлений: 1)
Ответ на: комментарий от Nasvay28

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

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

def is_valid_string(s):
    "Возвращает True, если строка содержит только разрешённые буквы"
    for x in s:
        if x - недопустимая буква:
            return False
    return True

def copy_valid_items(lst):
    r = []
    for x in list:
        if is_valid_string(x):
            r.append(x)
    return r

Это не идиоматический Python, а скорее указание на способ декомпозиции задачи.

Begemoth ★★★★★
()
Ответ на: комментарий от Nasvay28

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

Сам я не питонист, а код уже предложили. Добавлю только, что сначала надо написать рабочий корректный код, пусть даже неэффективный, а потом уже его оптимизировать. Причём оптимизировать только тогда, когда он действительно работает неприемлемо медленно. А оптимизировать примерно так: выявляешь самые узкие места путём замеров времени и оптимизируешь только их, а не вообще что угодно. А там могут быть разные варианты:

1. Улучшение алгоритма — самое действенное.

2. Замена вызовов функций на вставки — менее действенно.

3. В крайнем случае написание узкого места на другом языке.

aureliano15 ★★
()
Ответ на: комментарий от anonymous

Если вставлю брейк, то если первый символ совпадает с разрешенными, то остальные вообще проверятся не будут.

Nasvay28
() автор топика
Ответ на: комментарий от aureliano15

Готовый вариант есть. Тупо пихнуть в set() все что в итоге входит в новый список. Но это грубо и лишне, как по мне.

Nasvay28
() автор топика
Ответ на: комментарий от Begemoth

Да, это работает. И да, я могу так же решить вопрос. Как уже писал, мне было интересно, можно ли прямо в том лупе, который у меня описан, закидывать подходящие элементы в новый список. Я так же могу описать через удаление из копии списка. Понял ты правильно, и написал все верно, но вопрос таки был чуть-чуть в другом.

Nasvay28
() автор топика
Ответ на: комментарий от Nasvay28

А вообще правильную методику оптимизации уже описали выше, далеко не факт, что тут надо именно вызов функции оптимизировать.

Begemoth ★★★★★
()
Ответ на: комментарий от Begemoth

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

Nasvay28
() автор топика
Ответ на: комментарий от Nasvay28

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

Begemoth ★★★★★
()
Ответ на: комментарий от Nasvay28

Еще раз for-else. else относящийся к for выполняется только если цикл завершился не по break.

Begemoth ★★★★★
()
Ответ на: комментарий от Nasvay28

Это самое очевидное, что просится.

Сначала надо убедиться, что программа действительно работает неприемлемо медленно, а потом, если это так, отпрофилировать её ( вот статья на хабре о профилировании в питоне: https://habrahabr.ru/company/mailru/blog/202832/ ) и убедиться, что большую часть времени жрёт именно эта функция (а может другая жрёт ещё больше, тогда начинать оптимизацию надо с той другой). Ну и Begemoth посоветовал, если я правильно его понял, вместо прохода циклов попробовать регулярные выражения. А если он имел в виду не их, то я советую их попробовать. В питоне они должны быть и по идее могут оказаться быстрее циклов, т. к. реализованы на более низком уровне. Т. е. что-то вроде такого : «^[a-z]+$» проверяет строку на содержание только строчных латинских букв.

aureliano15 ★★
()

Если я тебя правильно понял, то так:

SUITABLE_LETTERS = string.ascii_letters + string.digits + string.punctuation + string.whitespace
def check_names(names):
    def letter_is_suitable(word):
        return all(letter in SUITABLE_LETTERS for letter in word)
    return list(filter(letter_is_suitable, names))

Это пердон 3, если чо.

Esper
()
Последнее исправление: Esper (всего исправлений: 1)

что мешает перед добавлением в список проверить на наличие в нем уже?

bvn13 ★★★★★
()
Ответ на: комментарий от Esper

Можно просто

return [name for name in names if all(letter in SUITABLE_LETTERS for letter in name)]

или регуляркой да.

pawnhearts ★★★★★
()
Ответ на: комментарий от Begemoth

А вообще почитай что-нибудь по декомпозиции - SICP для начала.

Лучше всего Кнута сразу.

Virtuos86 ★★★★★
()
import re

spisok_ludei = [...]
funkciya_filtr_ne_takaya_kak_u_espera = lambda chelovek: re.fullmatch('[!-~ \\s]*', chelovek, flags=re.ASCII)
noviy_spisok_ludei = list(filter(funkciya_filtr_ne_takaya_kak_u_espera, spisok_ludei))
# gotovo, dolzhno rabotat' namnogo bistree, chem u espera
# escho mozhno ispolzovat' re.compile pered lyambdoi

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.