Уведомления

Группа в Telegram: @pythonsu

#1 Март 14, 2017 07:10:34

PooH
От:
Зарегистрирован: 2006-12-05
Сообщения: 1948
Репутация: +  72  -
Профиль   Отправить e-mail  

Функция из ада и ее изгнание

Подтупляю, можно ли следующую функцию по питоничние записать?

  
def iter_points(r1, r2):
    seq1, seq2 = r1.points, r2.points
    a, b = next(seq1, None), next(seq2, None)
    while a or b:
        if a and b:
            if a > b:
                yield b, True
                b = next(seq2, None)
            else:
                yield a, False
                a = next(seq1, None)
        elif a:
            yield a, False
            a = next(seq1, None)
        else:
            yield b, True
            b = next(seq2, None)
Смысл: r1.points и r2.points генерируют упорядоченные последовательности данных, функция возвращает значения в правильном порядке и признак из какой последовательности они взяты. Что-то типа сортировки слиянием.



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

Офлайн

#2 Март 14, 2017 07:51:48

scidam
Зарегистрирован: 2016-06-15
Сообщения: 288
Репутация: +  35  -
Профиль   Отправить e-mail  

Функция из ада и ее изгнание

Здесь еще возможен момент, когда a=0 и b=0, при этом if a and b этого не уловит. Мне видится более менее симметричное решение такое

 def iter_points(seq1, seq2):
    while True:
        a, b = next(seq1, None), next(seq2, None)
        if a is not None and b is not None:
            yield (b, True) if a > b else (a, False)
        elif a is not None or b is not None:
            yield (a, False) if a is not None else (b, True)
        else:
            break

Отредактировано scidam (Март 14, 2017 07:52:04)

Офлайн

#3 Март 14, 2017 08:28:00

PooH
От:
Зарегистрирован: 2006-12-05
Сообщения: 1948
Репутация: +  72  -
Профиль   Отправить e-mail  

Функция из ада и ее изгнание

scidam
Здесь еще возможен момент, когда a=0 и b=0, при этом if a and b этого не уловит.
Спасибо, исправил, сколько уже лет на этом ловлюсь, неприятный момент в языке.

А по поводу варианта, мне кажется еще хуже, в моем варианте хоть брейка нет.



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

Офлайн

#4 Март 15, 2017 10:33:13

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9993
Репутация: +  857  -
Профиль   Отправить e-mail  

Функция из ада и ее изгнание

  
>>> class A: pass
... 
>>> r1 = A()
>>> r2 = A()
>>> 
>>> r1.points = [1, 4, 8]
>>> r2.points = [2, 5, 9]
>>> 
>>> 
>>> import itertools
>>> 
>>> sorted(itertools.chain(zip(r1.points, itertools.cycle('a')),
...                        zip(r2.points, itertools.cycle('b'))))
[(1, 'a'), (2, 'b'), (4, 'a'), (5, 'b'), (8, 'a'), (9, 'b')]
>>>



Офлайн

#5 Март 15, 2017 14:32:51

PooH
От:
Зарегистрирован: 2006-12-05
Сообщения: 1948
Репутация: +  72  -
Профиль   Отправить e-mail  

Функция из ада и ее изгнание

py.user.next
sorted
Это даст сложность n*log(n), у меня последовательности уже упорядочены, так что можно слить за n. Эта функция достаточно критична. Плюс хотелось бы остаться в генераторе.



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

Офлайн

#6 Март 15, 2017 16:05:47

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9993
Репутация: +  857  -
Профиль   Отправить e-mail  

Функция из ада и ее изгнание

Вот тебе функция слияния упорядоченных списков как пример

  
def merge(left, right):
    """Merge two lists in ascending order."""
    lst = []
    while left and right:
        if left[0] < right[0]:
            lst.append(left.pop(0))
        else:
            lst.append(right.pop(0))
    if left:
        lst.extend(left)
    if right:
        lst.extend(right)
    return lst
Обрати внимание, что вливание оставшихся элементов происходит за пределами цикла. Если у тебя в первом списке десять элементов, из которых все меньше любого элемента второго списка, а во втором списке миллион элементов, то не надо этот миллион элементов вливать с проверками, достаточно просто их влить. Перепишешь свой код с учётом этой инфы.

И второе
PooH
  
def iter_points(r1, r2):
    seq1, seq2 = r1.points, r2.points
Не надо подавать непонятно что в функцию, иначе ты эту функцию потом ни к чему больше не применишь. Надо упростить передаваемые данные. Это должны быть либо сами элементы, либо уже подготовленные элементы для возврата.

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

Вот пример, сортировку слиянием я написал в 2013 году (4 года назад)
[guest@localhost funcs]$ stat -c %y merge.py 
2013-03-05 10:53:48.000000000 +1100
[guest@localhost funcs]$

И вот я её беру и сортирую твои точки, про которые тогда я, естественно, и не предполагал
  
>>> def merge(left, right):
...     """Merge two lists in ascending order."""
...     lst = []
...     while left and right:
...         if left[0] < right[0]:
...             lst.append(left.pop(0))
...         else:
...             lst.append(right.pop(0))
...     if left:
...         lst.extend(left)
...     if right:
...         lst.extend(right)
...     return lst
... 
>>> 
>>> import itertools
>>> 
>>> class A: pass
... 
>>> r1 = A()
>>> r2 = A()
>>> 
>>> r1.points = [1, 4, 8]
>>> r2.points = [2, 5, 9]
>>> 
>>> merge(list(zip(r1.points, itertools.cycle('a'))), list(zip(r2.points, itertools.cycle('b'))))
[(1, 'a'), (2, 'b'), (4, 'a'), (5, 'b'), (8, 'a'), (9, 'b')]
>>>
Мне не надо ничего писать, я просто взял функцию без каких-либо изменений и сразу использовал. Точно так же я делал здесь программу для сохранения закладок из Chrome. У меня была программа по сохранению закладок из Firefox, я взял из неё кусок, поменял в нём содержимое только одной функции (из примерно десяти функций) и применил к json-данным из Chrome - и всё сработало, как часы. За десять минут я написал новую программу, которая не планировалась изначально.



Офлайн

#7 Март 15, 2017 16:58:01

PooH
От:
Зарегистрирован: 2006-12-05
Сообщения: 1948
Репутация: +  72  -
Профиль   Отправить e-mail  

Функция из ада и ее изгнание

py.user.next
Обрати внимание, что вливание оставшихся элементов происходит за пределами цикла.
Еще раз повторю, у меня генераторы, т.е. две потенциально бесконечных ленты сливаются в одну. Которая, в свою очередь идет дальше. И да, одна из лент может внезапно оборваться.
py.user.next
Перепишешь свой код с учётом этой инфы.
Ээээ… как бы помягче сказать, это не явилось для меня откровением.
py.user.next
Не надо подавать непонятно что в функцию, иначе ты эту функцию потом ни к чему больше не применишь.
Ну, таки, не библиотеку пишу. Вряд ли в ближайшем времени попадется снова такая структура. Да и функцию сравнения тогда надо выносить в параметры, а вызов функции дорого стоит.



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

Офлайн

#8 Март 15, 2017 17:22:02

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9993
Репутация: +  857  -
Профиль   Отправить e-mail  

Функция из ада и ее изгнание

PooH
И да, одна из лент может внезапно оборваться.
Да, и вторая лента будет миллион раз проверяться. Ты же говорил о сложности, а сам миллион пустых проверок допускаешь.

PooH
Вряд ли в ближайшем времени попадется снова такая структура.
Это общее правило при написании функций, про сцепление модулей не слышал? У тебя функция привязана к формату. Если поменяешь, допустим, объект вот этот, в котором точки, то функцию придётся выкинуть, потому что она не подцепит новую форму. Надо будет менять функцию, залазить внутрь и что-то там писать. И, соответственно, если у тебя таких функций сто, то ты должен каждую выкинуть. Будешь просто сидеть и сто новых функций писать. А мог бы сидеть и новые фичи писать.



Офлайн

#9 Март 16, 2017 09:33:32

PooH
От:
Зарегистрирован: 2006-12-05
Сообщения: 1948
Репутация: +  72  -
Профиль   Отправить e-mail  

Функция из ада и ее изгнание

py.user.next
Да, и вторая лента будет миллион раз проверяться. Ты же говорил о сложности, а сам миллион пустых проверок допускаешь.
Уговорил, чорт языкатый! Оно и симпатишней получилось.
  
def merge_sequences(right, left):
    a, b = next(right, None), next(left, None)
    while not (a is None or b is None):
        if a[0] > b[0]:
            yield b, True
            b = next(left, None)
        else:
            yield a, False
            a = next(right, None)
    rest, value, side = (right, a, False) if a else (left, b, True)
    while value:
        yield value, side
        value = next(rest, None)



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

Офлайн

#10 Март 16, 2017 10:00:25

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9993
Репутация: +  857  -
Профиль   Отправить e-mail  

Функция из ада и ее изгнание

PooH
Оно и симпатишней получилось.
Алгоритмически оно выпрямилось, а графически как-то всё шиворот-навыворот (не читается легко). Лево справа, а право слева. И индексы зачем-то. Там либо индексы с уже помеченными элементами, либо True/False должно быть. И второй while должен так же на None проверять, так как в точках может 0.0 оказаться и цикл подумает, что это конец.



Отредактировано py.user.next (Март 16, 2017 10:04:48)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version