Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.205.56.209] |
|
Сообщ.
#1
,
|
|
|
Тестовый массив строк
std::string str[] = {"строка", "01строка", "09строка", "04строка", "03строка", "01строка", "09строка", "05строка", "03строка", "строка", "01строка", "06строка", "03строка", "06строка", "09строка", "строка", "01строка", "05строка", "строка", "04строка", "строка", "09строка"}; Прикреплённый файлvsTestCpp_Forum.zip (2,12 Кбайт, скачиваний: 27) |
Сообщ.
#2
,
|
|
|
Вот тебе решение. Правда я воспользовался std::vector, т.к. работаем с С++ и не будем тянуть Си-шный гемор.
#include <iostream> #include <sstream> #include <iomanip> #include <vector> #include <map> int main(int argc, char* argv[]) { std::vector<std::string> str = {"строка", "01строка", "09строка", "04строка", "03строка", "01строка", "09строка", "05строка", "03строка", "строка", "01строка", "06строка", "03строка", "06строка", "09строка", "строка", "01строка", "05строка", "строка", "04строка", "строка", "09строка"}; // служебная "карта" std::map<std::string, uint64_t> map; // выходной массив std::vector<std::string> out; // собираем выходной массив for(auto &&i:str) { map[i] = (map.count(i) > 0) ? map[i] + 1 : 1; std::ostringstream oss; oss << '_' << std::setfill('0') << std::setw(3) << map[i]; out.push_back(i + oss.str()); } // печать выходнго массива for(auto &&i:out) { std::cout << i << std::endl; } return 0; } Вывод: строка_001 01строка_001 09строка_001 04строка_001 03строка_001 01строка_002 09строка_002 05строка_001 03строка_002 строка_002 01строка_003 06строка_001 03строка_003 06строка_002 09строка_003 строка_003 01строка_004 05строка_002 строка_004 04строка_002 строка_005 09строка_004 Онлайн исполнение гляди тут. |
Сообщ.
#3
,
|
|
|
Спасибо большое за код! Буду в нем разбираться - не использовал раньше auto и map. Раньше программировал на C#, а C++ только сейчас стал изучать.
|
Сообщ.
#4
,
|
|
|
Цитата tumanovalex @ Мне не удалось придумать алгоритм решения этой задачи. Алгоритм может быть и таким - проведём сортировку строк. Одинаковые строки будут располагаться по-очереди. Значит, в результате сортировки получим группы одинаковых, следующих одна за другой. Надо будет запомнить индекс расположения каждой строки. Тут можно сделать структуру индекс + строка. И сортировать массив таких структур, но по строкам. Зная индекс, после сортировки и преобразования можно правильно заполнить массив с результатами. |
Сообщ.
#5
,
|
|
|
Я попробовал использовать вектор с парой (std:vector < pair<string, unsigned int>> vsn), потом сортировал вектор. В результате он отсортировался по строке в правильном порядке. Но потом возникла задача правильно добавить элементы в выходной массив, решение которой тоже потребовало дополнительного кода. Может быть это потому, что я плохо разбираюсь в C++.
С кодом Majestio я разобрался. По-моему, короче, чем у него, решения задачи не получится. Решение замечательное, я бы такое не придумал. |
Сообщ.
#6
,
|
|
|
Цитата Majestio @ Тут map[i] слева может быть вычислено до map.count(i), что может ошибочно повести код по ветке > 0, если ключ только-только был создан. Как вариант, ?: можно заменить на if(), и проблем с порядком вычислений подвыражений не будет, но к счастью тут достаточно простого map[i] = (map.count(i) > 0) ? map[i] + 1 : 1; ++map[i]; |
Сообщ.
#7
,
|
|
|
Цитата Qraizer @ Тут map[i] слева может быть вычислено до map.count(i), что может ошибочно повести код по ветке > 0, если ключ только-только был создан. Интересно. Аргументируй плс Добавлено Цитата Qraizer @ но к счастью тут достаточно простого ++map[i]; Да, так будет гораздо симпатичнее. for(auto &&i:str) { std::ostringstream oss; oss << '_' << std::setfill('0') << std::setw(3) << ++map[i]; out.push_back(i + oss.str()); } На счет обращения к элементу с несуществующим ключом - буду знать) |
Сообщ.
#8
,
|
|
|
Спасибо всем ответившим!
|
Сообщ.
#9
,
|
|
|
Цитата tumanovalex @ Но потом возникла задача правильно добавить элементы в выходной массив, решение которой тоже потребовало дополнительного кода. Может быть это потому, что я плохо разбираюсь в C++. Вот именно. Чтобы получить опыт, надо больше работать. Поэтому задачу можно модифицировать: Если будет найдено 5 алгоритмов и сделано 5 реализаций - то это 5 Если 4 - оценка "хорошо". Меньше 3-х - это "незачёт", всё сначала. |
Сообщ.
#10
,
|
|
|
Постараюсь работать больше и пытаться решать задачи разными способами
|
Сообщ.
#11
,
|
|
|
Цитата Majestio @ Операнды в выражении между точками следования могут вычисляться в произвольном порядке. Это операции обязаны выполняться в строгом порядке, но вот подготовка операндов для них не обязана соблюдать порядок их появления в выражении. Для операций присваивания есть дополнительное требование, что само присваивание выполняется после вычисления обоих операндов и перед формированием результата самой операции (спецом для каких-нибудь a=b=c+d, где результат b=c+d используется как правый операнд в присваивании a=), но нет требования вычислять правый операнд обязательно ранее левого.Интересно. Аргументируй плс P.S. Замечу, что в ?: вводится точка следования после вычисления условия, так что второй map[i] проблемы переупорядочивания с map.count(i) не имеет. |
Сообщ.
#12
,
|
|
|
Но ведь конструкция
map[i] = (map.count(i) > 0) ? map[i] + 1 : 1; |
Сообщ.
#13
,
|
|
|
Не могу. Не от моего желания зависит, а от желания компилятора.
Добавлено Но можно сэмулировать на чём-то более простом. #include <iostream> int x[] = { 123, 456 }, *ptr = x; int *print(const char* msg, int *ptr) { std::cout << msg << ", arg is " << ptr << std::endl; return ptr; } int main() { *print("pred", ptr) = *print("post", ptr++); std::cout << x[0] << ' ' << x[1] << std::endl; } D:\Work\delMe>cl -EHs -O1 -Fa q.cpp Оптимизирующий компилятор Microsoft (R) C/C++ версии 19.36.32534 для x86 (C) Корпорация Майкрософт (Microsoft Corporation). Все права защищены. q.cpp Microsoft (R) Incremental Linker Version 14.36.32534.0 Copyright (C) Microsoft Corporation. All rights reserved. /out:q.exe q.obj D:\Work\delMe>q post, arg is 009B1000 pred, arg is 009B1004 123 123 D:\Work\delMe>cl -EHs -O2 -Fa q.cpp Оптимизирующий компилятор Microsoft (R) C/C++ версии 19.36.32534 для x86 (C) Корпорация Майкрософт (Microsoft Corporation). Все права защищены. q.cpp Microsoft (R) Incremental Linker Version 14.36.32534.0 Copyright (C) Microsoft Corporation. All rights reserved. /out:q.exe q.obj D:\Work\delMe\q>q pred, arg is 00D43004 post, arg is 00D43000 123 123 P.S. Это минимальный пример. Стоит его чуть упростить, например, выкинуть печать x[], эффект пропадает. |
Сообщ.
#14
,
|
|
|
Не не , речь только о "?:" Я почитал, что для выражения "?:" точка следования появляется сразу после вычисления "условия". В нашем этом случае m.count(i) никаких модификаций не производит. Следовательно далее будет выполняться либо 2-е выражение, либо 3-е, в зависимости от 1-го. Как результат - никаких побочек не будет. Потенциальная "дырка" - предвычисление в блоке сравнение (до появления этой первой точки следования). Но у меня тут все ровно.
|
Сообщ.
#15
,
|
|
|
А. Ну да. Я ж так в P.S. и написал, что с ?: проблемы нет. В отличие от =. Левый для = операнд map[i] может быть вычислен раньше, чем начнётся вычисляться правый операнд =, поэтому map.count() уже насчитает 1. Благо, инициализирующее значение по умолчанию для decltype(map)::mapped_type будет равно 0, поэтому отработав true для ?:, получим ту же 1, что и для false. И тем не менее, дефект в коде есть, просто в данном конкретном случае он не приводит в багу. Зато в аналогичной ситуации в другом окружении запросто сможет.
|