Пишу, по большей части, про историю, свою жизнь и немного про программирование. Живу в Казани.

Программируем с GPT

Мне всё-таки кажется, что в интернете достаточно примеров как замечательно нейросети справляются с программированием, надо восстанавливать баланс. Свежий пример из моей практики.

Нужно было переписать вот такой код с «Пайтона» на «Си++»:

{72: 65, 80: 66}.get(value, 0)

Что тут происходит? Если value равно 72, вернуть 65, если 80, то 66, иначе ноль. Нужно мне это, если вкратце, для преобразования виндовых кодов в линуксовые.

Так как Си++ я не знаю, описал на Пайтоне — так быстрее и проще показать, что код мне нужен компактный — хочется не городить switch, а добавлять новое правило как можно проще.

Вот что мне сгенерировал ChatGPT-4:

int value = 72;
std::map<int, int> mymap = {{72, 65}, {80, 66}};
int result = mymap.count(value) ? mymap[value] : 0;

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

Во-первых, вместо map надо использовать unordered_map, сложность поиска по первой структуре логарифмическая, по второй — константная в среднем.
Во-вторых, в этом коде надо использовать find, а не count, так как find остановится после первого совпадения (что нам и надо), а count — нет, продолжая тратить ресурсы.
В-третьих, map создаётся в этом примере каждый раз вместо одного. Хороший программист так это не оставит.

В итоге, код стал выглядеть следующим образом:

const static std::unordered_map<int, int> win2lin = {{72, 65}, {80, 66}};

auto it = win2lin.find(_getch());
ch = it == win2lin.end() ? 0 : it->second;
5 комментариев
Кирилл 1 мес

Для порядка отмечу, что поиск в map логарифмический по сложности, а в unordered_map константный в среднем, но линейный в худшем случае.

Евгений Степанищев 1 мес

Спасибо, посмотрел чат, действительно, ребята писали про логарифмический (а про линейный в худшем не писали). Сейчас поправлю.

deadem 1 мес

Не могу спокойно смотреть тут ни на map, ни unordered_map. Так-то оно, конечно, ближе по духу к Пайтону, но у мэпов очень большой константный множитель, из-за чего их эффективность выстрелит только на достаточно больших списках. Тут же и проще и быстрее использовать просто массив.

Вот, компилятор прекрасно справляется вообще убрать все циклы и заменить их просто на пару сравнений: https://godbolt.org/z/8sW8xc7e8

А вот как выглядит то же самое на unordered_map: https://godbolt.org/z/TWcq6ooeb

Но заставить Chat 3.5 написать вместо map что-то вменяемое никак не получилось... Какую-то жуть всё время предлагает.

Евгений Степанищев 1 мес

Я совсем не против реквестов в репозиторий, тем более, как я говорил много раз ранее — я не знаю Си++, просто хотелось как-то дёшево записать, чтобы при нужде потом просто было пару чисел добавить )

P. S. Код исправил на ваш.

Хельги 1 мес

Не хватает контекста. Сейчас два значения, а сколько ожидается, 5, 15, 100? Кажется, от этого зависит, какой сложности огород городить. Для двух значений и if сгодился бы.

Евгений Степанищев 1 мес

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

Евгений Суреев 1 мес

В-третьих, map создаётся в этом примере каждый раз вместо одного.

Я не уверен, но вроде в Питоне тоже каждый раз словарь будет создаваться.

Евгений Степанищев 1 мес

Это от оптимизаций зависит, разумеется, но без оптимизаций — конечно. Это же изменяемый тип, он не интернируется.

Но хороший программист на Си++ так это точно не оставит.

al.zatv 1 мес

о май гад,больно смотреть:) если ты не написал иф для порядка пяти значений, а написал map или unordered_map, то у тебя больше нет права жаловаться на неэффективность:)

Евгений Степанищев 1 мес

))) я понимаю, что map/unordered_map тут из пушки по воробьям, но из песни слов не выкинешь — таков результат обсуждения этого кода в чате с кожаными программистами. Эффективность мне не нужна, кстати, мне нужен компактный способ записывать пары значений — из чего во что переходит.