Уведомления

Группа в Telegram: @pythonsu
  • Начало
  • » Центр помощи
  • » в результате выполнения кода создаются лишние списки, вложенные в друг друга [RSS Feed]

#1 Авг. 31, 2015 01:43:22

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

в результате выполнения кода создаются лишние списки, вложенные в друг друга

Сравнение одних merge():

#!/usr/bin/env python3
 
import timeit
 
def prepare1():
 
    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
 
    return merge
 
def prepare2():
 
    def merge(a,b):
        a, b = iter(a), iter(b)
        def gen(a, b):
            vb = next(b)
            try:
                while 1:
                    va = next(a)
                    if va > vb: va, vb, a, b = vb, va, b, a
                    yield va
            except: yield vb
        yield from gen(a, b)
        yield from a
        yield from b
 
    return merge
 
def prepare3():
 
    def merge(a,b):
        a, b = iter(a), iter(b)
        try:
            vb = next(b)
            try:
                while 1:
                    va = next(a)
                    if va > vb: va, vb, a, b = vb, va, b, a
                    yield va
            except: yield vb
            yield from b
        except: yield from a
 
    return merge
 
merge1 = prepare1()
merge2 = prepare2()
merge3 = prepare3()
 
lst1 = list(range(1, 100000, 2))
lst2 = list(range(2, 100001, 2))
lst11 = list(range(1, 100000, 2))
lst22 = list(range(2, 100001, 2))
lst111 = list(range(1, 100000, 2))
lst222 = list(range(2, 100001, 2))
 
def f1():
    merge1([], [])
    merge1([1, 3, 5], [2, 4, 6])
    merge1(lst1, lst2)
 
def f2():
    list(merge2([], []))
    list(merge2([1, 3, 5], [2, 4, 6]))
    list(merge2(lst11, lst22))
 
def f3():
    list(merge3([], []))
    list(merge3([1, 3, 5], [2, 4, 6]))
    list(merge3(lst111, lst222))
 
def main():
    t1 = timeit.Timer('f1()', 'from __main__ import f1')
    t2 = timeit.Timer('f2()', 'from __main__ import f2')
    t3 = timeit.Timer('f3()', 'from __main__ import f3')
     
    for t in t1, t2, t3:
        print(t.repeat(3, 100))
 
if __name__ == '__main__':
    main()

[guest@localhost py]$ ./mergecmp1.py 
[0.6375549949998458, 0.0005647759999192203, 0.0005668369994964451]
[4.651441780999448, 4.622966723999525, 4.6205978140005755]
[3.620450236000579, 3.6205695090002337, 3.611680899000021]
[guest@localhost py]$

Isem
где хранится прицепленный к структуре массив?
В динамической памяти там обычно хранится всё. (Это чтобы была возможность что-то удалять и освобождать память из под этого.)

Isem
В действительности (это неявно), взятие среза у списка - это одна операция, которая создает новый список, а взятие среза у тьюпла - это другая операция, которая создает новый тьюпл.
Эти операции синтаксически одинаковые и означают “прочитать часть объекта”. То, что они по разному выполняются, - это обычный полиморфизм, до которого нам дела нет. Ты сказал, что операции со списком и кортежем не отличаются по скорости, если это операции чтения. Вот тебе операция взятия среза, под операцию записи она не подпадает, потому что список не меняется.

Isem
Ключевое слово в этой фразе: теоретизировал. Считаем, что ты говоришь за себя о себе, а не о других.
Ну, не знаешь ты C, не примазывайся. Если изучал C++, то C ты не знаешь. А если думаешь, что знаешь, то ты заблуждаешься. Потому что они разные и всё там работает по-разному.

Isem
Итератолры пошли великолепно (особенно по сравнению с вызовом pop первого элемента в цикле), потому что скорость работы merge увеличилась в десятки раз.
В общем, с чего ты взял, что в десятки раз? Как замерял?
Я думаю, ты их не тождественно замерил. Вверху показано, что в 6-8 раз.

Isem
Мы же (то есть ты), стал тестировать mergesort (не inplace), на основе такой же merge (то есть не inplace).
А кому нужна merge() без mergesort() ? Ты ещё скажи взять какую-нибудь часть из merge() и потестировать её. В том-то и дело, что никому эта функция не нужна, она вспомогательная. И как показали результаты, никакого существенного преимущества итераторный вариант не даёт, только код делает нечитаемым.

Isem
У Кнута, кстати, подробно рассмотрены десятки алгоритмов сортировки, рекомендую.
Это ты его читал или тоже где-то в теории читал, что у Кнута много сортировок? ;)

Isem
Вот эот pop и делает алгоритм merge ужасно неэффективным.
Фантазии, фантазии… Комарик сел - комарика прихлопнули.

Isem
С итерабельным вариант готов, осталось все то же самое сделать inplace и довести их до совершенства. Кто начнет? Готов?
Да, давай, взялся за гуж, не говори, что не дюж :)

Isem
А бессмысленную полемику предлагаю отставить.
Да можно и оставить, мне просто жалко тебя, я как представлю, какой это получится быдлокодище (ты, кстати, исключение в merge() отловил, как новичок), то я просто вижу, как ты смотришь на этого монстра и думаешь “нафиг я всё это писал”. Так оно ещё потом и получится медленным - двойной удар.

Isem
Чтобы написать оптимальный код, надо представлять что происходит на уровне команд процессора (CPU то есть).
Это ещё зачем? И как ты представишь, если программа на питоне переносится на разные архитектуры?



Офлайн

  • Начало
  • » Центр помощи
  • » в результате выполнения кода создаются лишние списки, вложенные в друг друга[RSS Feed]

Board footer

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

Powered by DjangoBB

Lo-Fi Version