Форум сайта python.su
Подтупляю, можно ли следующую функцию по питоничние записать?
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)
Офлайн
Здесь еще возможен момент, когда 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)
Офлайн
scidamСпасибо, исправил, сколько уже лет на этом ловлюсь, неприятный момент в языке.
Здесь еще возможен момент, когда a=0 и b=0, при этом if a and b этого не уловит.
Офлайн
>>> 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')] >>>
Офлайн
py.user.nextЭто даст сложность n*log(n), у меня последовательности уже упорядочены, так что можно слить за n. Эта функция достаточно критична. Плюс хотелось бы остаться в генераторе.
sorted
Офлайн
Вот тебе функция слияния упорядоченных списков как пример
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
[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')] >>>
Офлайн
py.user.nextЕще раз повторю, у меня генераторы, т.е. две потенциально бесконечных ленты сливаются в одну. Которая, в свою очередь идет дальше. И да, одна из лент может внезапно оборваться.
Обрати внимание, что вливание оставшихся элементов происходит за пределами цикла.
py.user.nextЭэээ… как бы помягче сказать, это не явилось для меня откровением.
Перепишешь свой код с учётом этой инфы.
py.user.nextНу, таки, не библиотеку пишу. Вряд ли в ближайшем времени попадется снова такая структура. Да и функцию сравнения тогда надо выносить в параметры, а вызов функции дорого стоит.
Не надо подавать непонятно что в функцию, иначе ты эту функцию потом ни к чему больше не применишь.
Офлайн
PooHДа, и вторая лента будет миллион раз проверяться. Ты же говорил о сложности, а сам миллион пустых проверок допускаешь.
И да, одна из лент может внезапно оборваться.
PooHЭто общее правило при написании функций, про сцепление модулей не слышал? У тебя функция привязана к формату. Если поменяешь, допустим, объект вот этот, в котором точки, то функцию придётся выкинуть, потому что она не подцепит новую форму. Надо будет менять функцию, залазить внутрь и что-то там писать. И, соответственно, если у тебя таких функций сто, то ты должен каждую выкинуть. Будешь просто сидеть и сто новых функций писать. А мог бы сидеть и новые фичи писать.
Вряд ли в ближайшем времени попадется снова такая структура.
Офлайн
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)
Офлайн
PooHАлгоритмически оно выпрямилось, а графически как-то всё шиворот-навыворот (не читается легко). Лево справа, а право слева. И индексы зачем-то. Там либо индексы с уже помеченными элементами, либо True/False должно быть. И второй while должен так же на None проверять, так как в точках может 0.0 оказаться и цикл подумает, что это конец.
Оно и симпатишней получилось.
Отредактировано py.user.next (Март 16, 2017 10:04:48)
Офлайн