Предыдущий пост Поделиться Следующий пост
Обман сознания
lex_kravetski
Поставил эксперимент. Точнее, он сам случайно поставился.

Довольно простая задача. Есть массив (или какой-то ещё список) с элементами. Назовём его elements. Есть массив с несколькими индексами. Назовём его indices. Нужно получить новый массив, в который войдут те элементы из elements, индексы которых содержались в indices. Проще говоря, из полного набора элементов выбрать, скажем так, заселекченные.

Удивительно, но несколько моих знакомых программистов практически в один голос начали с примерно такого маршрута: будем итерировать от 0 до elements.size и для каждого номера проверять, есть ли он в indices. Если есть — добавлять соответствующий элемент в новый массив. Точнее, нет, будем итерировать по elements и увеличивать на единицу счётчик. Проверять, есть ли, добавлять текущий. Точнее, нет, добавим содержимое indices в Set, чтобы быстрее проверять.

Я и сам машинально пошёл сначала по этому маршруту — именно поэтому и решил провести подобный эксперимент. Почему так происходит — не знаю. Видимо, от сильной привычки извёрнуто итерировать.

Хотя на самом деле решение мега-тривиальное: итерируем по indices, и добавляем в новый буфер массива elements(indices(i)). Тривиальное, но приходит оно почему-то вторым по счёту, а не первым. «Снимаем чайник с плиты, выливаем из него воду и таким образом приводим задачу к уже решённой».

На Scala решение записывается совершенно очаровательной в своей простоте конструкцией.

indices map elements

Смысл в том, что поскольку массив indices — коллекция, для неё определена операция map. То есть, преобразование коллекции путём преобразования каждого её элемента при помощи переданной в аргумент функции. Но функция извлечения из скала-коллекции — это просто apply, то бишь, при вызове — просто индекс в скобках после имени переменной: elements(i).

Полная запись была бы такой:

indices.map(i ⇒ elements(i))

Однако для такого тривиального случая есть и сокращённый вариант записи. Приведённый выше. Имя ссылки на контейнер одновременно может выступать и как имя функции от одного аргумента с параметром типа Int.

Последующий эксперимент показал, что эта простая запись — настолько простая, что некоторых людей способна ввести в прострацию и заставить искать в ней какой-то подвох.

Очевидное неочевидное.

Странно. Мне по прочтении задачи пришло в голову именно elements(indices(i))... Видимо, потому что я ста-арый программер и новым языкам не обучен.

Эксперимент надо углу́бить — проверить отдельно для императивных программистов, отдельно для объектных и отдельно для функциональных.

думаю, что первое решение может прийти в голову потому, что оно более обобщенное.

Любой более менее опытный программист всегда пытается думать на шаг-два вперед: «а что будет если надо будет отобрать не просто элементы из indices, а ещё и какое-нибудь условие применить.»

Это как предварительная гипотеза, почему это решение первым всплывает.

Но оно неправильное, потому что в indices один порядок элементов, а в elements другой.

Сохранение порядка не требовалось.

В голову ничего не пришло, так как это уже есть в языке:
   a=:10 20 30 40 50
   b=:0 2 2 4
   b{a
10 30 30 50

Аналогично
> a <- c(10,20,30,40,50)
> b <- c(1,3,3,4)
> a[b]
[1] 10 30 30 40

На Python: [elements[i] for i in indices]

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

А если indices рассматривать как массив инкрементов указателя на elements, так вообще кайф )

Я, разумеется, начал с перебора indices.

У вас очень удивительные знакомые программисты. Мало того, что их решение слишком затратное, так оно ещё и не правильное.

Вот именно, для знающего С/C++ и Матлаб первый способ какой-то странный.
В Матлабе второй способ вообще самый интуитивный.

Не программист (хотя программки для научных расчетов пописывал), но первый вариант даже в голову не приходил, только второй.

Зато, мы теперь точно знаем, что у Лекса есть знакомые индусы.

меня уже на том месте, где идет описание алгоритма, по которому пошли друзья, посетила кома.
дальше читать не мог.
ну срез массива же.
понятно, что не во всех языках есть такая штука, но все-таки.

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

Странные какие-то у вас там программисты.

Этих ваших скал не знаю.

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

Edited at 2013-01-05 16:08 (UTC)

Куда хуже то, что знакомые–индусы сразу сели писать код, не уточнив задачу — нужны на выходе повторы или нет. Это полная жопа: они либо напишут неправильный код и будут часами его отлаживать, либо по ходу дела будут доставать старших уточнениями. В обоих случаях — пустая трата времени и денег.

(Удалённый комментарий)
Если это “какой-то ещё список”, а не массив, то обращение к его элементам по индексу может содержать перебор внутри себя, и тогда второй способ практически превратится в первый.

А для массива всё верно.

Не превратится. В этом случае второй способ станет гораздо более затратным, чем первый. Однако размышлять об индексах в неиндексированной коллекции — всё равно что уточнять, не null ли у нас тут каждая из ссылок.

Дорогие комментаторы. Спасибо что опять меня в дураки записали, в одну группу с Алексеем Краветским.

Причина деградации программеров (если, конечно, они изначально не были алгоритмическими идиотами, что встречается нередко) кроется в использовании языков очень высокого уровня. Что развращает и отупляет.

Должен отметить, что на языках высокого уровня граждане, привыкшие к чему-то типа С, пишут крайне хреновые алгоритмы. У них неплохо получается частное и локальное, но вот глобальное и обобщённое — плохо.

?

Log in

No account? Create an account