Pull to refresh

Comments 31

Жаль нет сравнения памяти/времени, необходимых для каждого способа

А смысл? Если вам важно сколько времени и памяти уходит на всё это, то лучше использовать не Python, а что-нибудь другое.

Python — это для случаев, когда в первую очередь важна читаемость…

Следуя Вашей логике код на питоне никогда не стоит оптимизировать

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

Я сначала тоже подумал про время. Но математически нельзя сделать подобную проверку не пройтись по всем элементам, так что кажется все эти подходы в лучшем случае все равно дают O(n). Поправьте если сморозил глупость

Почему это нельзя не пройтись, при первом же отличном элементе заканчивать проход, так что полный проход будет только в худшем случае.
В лучшем случае О(1), амортизированное время всё равно O(n)
> 6. Одним из креативных подходов к решению этой задачи является перестановка элементов. Мы меняем элементы местами и проверяем, что список из-за этого не изменился. Это говорит нам о том, что все элементы в списке — одинаковые. Вот пару примеров такого подхода:

Палиндромы? Не, не слышали.
Палиндромы также верно определятся приведённой функцией. Всё, что там «переставляется» — первый элемент в конец списка. Сравнение
elements[1:] == elements[:-1]
— это просто другой способ написать «второй элемент равен первому, третий — второму, ..., последний — предпоследнему».
О, спасибо. Сослепу принял `elements[1:] == elements[:-1]` за `reverse`. Да и описание `перестановка элементов` вводит в заблуждение.
>>> elements = [1, 2, 1] # палиндром
>>> elements[1:]
[2, 1]
>>> elements[:-1]
[1, 2]
>>> elements[1:] == elements[:-1]
False

О, паралимпиада, люблю ) Кот претендует на медаль в номинации "уникального и необычного" ) Питон не знаю, но алгоритм тривиально пишется на любом языке, напишу на сях )


bool f (int *m, int b, int e) {
    int c=(b+e)/2;
    return b>=e ? true : b+1==e ? m[b]==m[e] : f(m,b,c) && f(m,c,e);
}

А вообще надо вводить новый моноидальный тип и решать эту задачу как свертку структуры по моноиду. Ибо в таком случае умный компилятор сумеет сам распараллелить процесс на нужное число потоков/ядер и порвать по бенчмаркам все предложенное.

Помилуйте, это же паралимпиада, а не соревнование по обфускации :)
return len(elements) == elements.count(elements[0])

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


Пройтись по списку в цикле c "return false if (elem[i] != elem[0]); return true if (достигнут последний элемент)"? Нет, не слышали.

дофигиллион циклов
А вы, видимо, не слышали об O-нотации. Оба решения — линейны и ваше решение всего, в среднем, в два раза быстрее. А если count написан на каком-нибудь более быстром языке, то и вовсе может оказать, что ваше предложение медленнее.
Не программировал на Питоне, но у ЯВУ, в которых радеют за выразительность, как правило, есть проблема в том, что все операторы написаны не на самом языке и поэтому быстрые, а сам язык — медленный. Получается такая штука: если есть какой-то специальный оператор, пусть и молотящий в 10 раз больше действий, чем надо, то он всегда на порядок будет быстрей, чем его же реализация на этом языке в модификации с уменьшенным количеством действий. Получается довольно извращённое программирование, когда микроскопами гвозди забивают и можно сделать это сотней способов, а вот, правильный и красивый алгоритм, это будет медленно. Надеюсь меня не заминусуют в хлам, это моё личное мнение.
Это не ваше личное мнение, это квинтэессенция питона и есть. Самая распространённая реализация — это интерпретатор, который примерно на два-три порядка медленнее, чем реализация того же, но не на самом питоне.

А дальше — всё, как вы сказали.
Минутка занудства
Два-три порядка пережить можно, избегать следует именно увеличения сложности.
1 → log(N) → N → N log(N) → N2 → N[3-x] → !N

Решения с аллокацией дополнительного массива в рамках этой задачи заставляют закипать что-то глубоко внутри меня.

Если бы оно было записано не на языке программирования, а именно как математическая демонстрация множественности решений — вообще никаких вопросов бы не возникло.

Два-три порядка пережить можно, избегать следует именно увеличения сложности.
1 → log(N) → N → N log(N) → N2 → N[3-x] → !N
Ну и где вы увидели в этой задаче «увеличение сложности»? Исходный массив — занимает O(N). Если мы в процессе работы не порождаем больше конечного числа массивов, то мы никакого «увеличения сложности», в общем, не получаем. Массивы временные, будут удалены сразу же.

Решения с аллокацией дополнительного массива в рамках этой задачи заставляют закипать что-то глубоко внутри меня.
Тем не менее для python'а — это нормально. Ибо там и просто массив целых будет занимать на порядок больше памяти, чем в C.

Если вы не хотите, чтобы аллокации производились «на каждый чих» — зачем вы вообще с этим языком связались?

Если бы оно было записано не на языке программирования, а именно как математическая демонстрация множественности решений — вообще никаких вопросов бы не возникло.
Ну это уже совсем другая история. Там можно и с сортировкой в N! мириться. А в обычной жизни — если вы выбрали python, то значит на константу — вам наплевать (хотя про bigO забывать не стоит).

elements[1:] == elements[:-1] кажется самым разумным выражением идеи…
> все операторы написаны не на самом языке и поэтому быстрые, а сам язык — медленный.

После чего, не знаю у кого как, а у меня немедленно возникает мысль — «а нахуа мне медленный язык?»

Про перевыделение памяти внутри «быстрых операторов» уже сказали выше.
После чего, не знаю у кого как, а у меня немедленно возникает мысль — «а нахуа мне медленный язык?»
Мысль-то правильная, а вот ответы на неё — бывают разные. Кому-то хочется, чтобы программа была короткой, кому-то хочется, чтобы в ней было меньше сущностей… да мало-то почему люди пишут не в машинных кодах, следя за использованием каждого бита?

Но если вы не хотите, чтобы в вашей программе использовалось памяти больше, чем необходимый минимум — то вам просто не нужно пользоваться Python'ом, вот и всё…

P.S. В конце-концов и bash-скрипты кто-то пишет, а уж этот, с позволения сказать, язык, раз в 100 медленнее Python'а будет…
Вы ещё скажите, что bat файлами никогда не пользовались, и по сей день, вместо исправления батника переписываете его на C++. Просто не надо путать программирование как разработку сложных систем и программирование как автоматизацию, хотя итоговый результат любого программирования, это автоматизация процессов и есть. Когда сама программа не нужна как ценность, а её можно просто выкинуть, после использования, это отличная ниша для выразительных языков и то что они развиваются в сторону языков для разрабоки, хуже их не делает, это проблема программиста — «когда остановиться» (Использование Кобола калечит разум), а не языка.
Тут Вы правы, но я ни разу не встречал задачи автоматизации, которая требовала бы логики сложнее «если флажок установлен, то делай это». Удостоверяться (в задачах автоматизации), что все элементы списка неизвестной длины равны одному, но неизвестному числу — ну вот ни разу не приходилось — было известно и первое, и второе.
Если у вас проблемы с автоматизацией, то посмотрите на AppleScript, там можно начертить что-нибудь в Индизайн, конвертунть в пдф, отправить почтой, проверить через бразуер что-то и т.п. Довольно сложные сценарии иногда реализуются и там везде объектный доступ. На Виндовс платформе, это наверное можно заменить AutoIt+VB и т.п.

Как я уже сказал: проблема в том, что все встречавшиеся мне проблемы автоматизации были чересчур простыми — то есть не требовали таких ухищрений, как в обсуждаемой статье. Деревья "если-то" (иногда очень кустистые, иногда с циклами) — да, а таких хитровыдуманных задач ну вот не было.

Честно говоря ИМХО в питоне важнее найти не много способов, а один, но самый выразительный, в данном случае самым привлекательным выглядит вариант с unique

А по-моему самый выразительный — через all. В задаче так и сказано: проверить, что "все" элементы равны.


Хотя я бы для выразительности убрал там разрезание списка на первый элемент и остаток (первый равен сам себе, 1 лишняя операция всего лишь):


return len(elements)==0 or all(x==elements[0] for x in elements)
согласен, этот вариант тоже хорош, думаю они равноценны
Sign up to leave a comment.

Articles