Russian Qt Forum

Программирование => С/C++ => Тема начата: Igors от Июль 02, 2019, 15:25



Название: Uniquer
Отправлено: Igors от Июль 02, 2019, 15:25
Добрый день

Есть контейнер возрастающих значений кратных 10, напр
Цитировать
vec[0] = 60
vec[1] = 70
vec[2] = 80
vec[3] = 100
vec[4] = 110
vec[5] = 1000
vec[6] = 1100
Нужна ф-ция которая бы "заполняла дырки" и возвращала заполненное значение не меньше фиксированного заданного min. Напр если min=50 то для контейнера выше ф-ция должна последовательно выдавать
Цитировать
50, 90, 120..9990, 1010..1090. 1110...
Др словами ф-ция вставляет в контейнер наименьшее уникальное значение кратное 10 и >= min

Спасибо


Название: Re: Uniquer
Отправлено: RedDog от Июль 04, 2019, 17:31
проще перегенерить его заново от мин значения через какой нибудь std::generate


Название: Re: Uniquer
Отправлено: Igors от Июль 05, 2019, 10:28
проще перегенерить его заново от мин значения через какой нибудь std::generate
Думаю что нет, не проще. А откуда вообще берется такая задача? Может Вы с ней уже встречались?  :)


Название: Re: Uniquer
Отправлено: RedDog от Июль 05, 2019, 19:14
проще перегенерить его заново от мин значения через какой нибудь std::generate
Думаю что нет, не проще. А откуда вообще берется такая задача? Может Вы с ней уже встречались?  :)
Бывают подобные задачи, например при вставке в БД, когда автоинкремент не совсем уместен.
Проще потому, что все равно "пустоты" надо как то проверять, а без беготни это никак не сделаешь, ну либо писать "аналог" БД и заводить индексы, того, чего нет, но это сомнительное решение.


Название: Re: Uniquer
Отправлено: Igors от Июль 06, 2019, 05:55
Проще потому, что все равно "пустоты" надо как то проверять, а без беготни это никак не сделаешь, ну либо писать "аналог" БД и заводить индексы, того, чего нет, но это сомнительное решение.
Неужели все так сложно? Десяток-другой строчек - уже проблема? Может просто "сделать" вместо поиска каких-то альтернатив?  :) Я пошел по пути наименьшего сопротивления и задействовал ассоциативный контейнер
Код
C++ (Qt)
struct Uniquer {
 
Uniquer( int start, int increment) :
mStart(start),
mIncrement(increment)
{
}
 
void Add( int value )
{
mSet.insert(value);
}
 
int Get( void )
{
auto it = mSet.lower_bound(mStart);
 
while ((it != mSet.end()) && (mStart == *it)) {
mStart += mIncrement;
++it;
}
 
int result = mStart;
mSet.insert(mStart);
mStart += mIncrement;
return result;
}
 
// data
std::set mSet;
int mStart, mIncrement;
};
 
Что вполне устраивает для моих нужд. Но все-таки std::set - удовольствие достаточно дорогое, да и много лишних данных хранится при интенсивной генерации, может и lower_bound нужен не всегда. С др стороны не хочется усложнять код. В общем, прошу блеснуть техникой  :)


Название: Re: Uniquer
Отправлено: RedDog от Июль 06, 2019, 09:13
Теперь осталось посчитать разницу в сложности алгоритмов между этим и std::generate.
У последнего О(N), даже в самых сложных условиях, кода одна строка, памяти не надо вообще.


Название: Re: Uniquer
Отправлено: Igors от Июль 06, 2019, 09:44
Теперь осталось посчитать разницу в сложности алгоритмов между этим и std::generate.
У последнего О(N), даже в самых сложных условиях, кода одна строка, памяти не надо вообще.
Я конечно понимаю что std - пуп земли, и облаять велосипедиста - дело святое, но причем тут std::generate  ??? Заглянем в справочник
Цитировать
template <class ForwardIterator, class Generator>
  void generate (ForwardIterator first, ForwardIterator last, Generator gen);

Generate values for range with function
Assigns the value returned by successive calls to gen to the elements in the range [first,last).

The behavior of this function template is equivalent to:

template <class ForwardIterator, class Generator>
  void generate ( ForwardIterator first, ForwardIterator last, Generator gen )
{
  while (first != last) {
    *first = gen();
    ++first;
  }
}
Не вижу как это вообще связано с темой
   



Название: Re: Uniquer
Отправлено: RedDog от Июль 06, 2019, 10:38
Все верно, ресайзим старый контейнер под новые нужды, и заполняем его без пробелов с шагом 10 через генератор, который этот шаг и выдаёт.


Название: Re: Uniquer
Отправлено: Igors от Июль 06, 2019, 12:31
Все верно, ресайзим старый контейнер под новые нужды, и заполняем его без пробелов с шагом 10 через генератор, который этот шаг и выдаёт.
Задача генерировать новое уникальное значение (ID), т.е. оно не должно совпадать ни с одним имеющимся (в контейнере).


Название: Re: Uniquer
Отправлено: RedDog от Июль 06, 2019, 12:46
Первоначально задача была заполнить дырки "от забора и до обеда". С шагом в 10.
При такой постановке, перегенерация от и до с шагом, была предложена выше.
Ну или задача поставлена была не полностью.


Название: Re: Uniquer
Отправлено: Igors от Июль 07, 2019, 11:11
Первоначально задача была заполнить дырки "от забора и до обеда". С шагом в 10.
Так и есть - ведь каждая заполненная дырка и есть новое уникальное ID, о чем прозрачно намекает и название темы.

При такой постановке, перегенерация от и до с шагом, была предложена выше.
Ну такое предложение не стоит воспринимать серьезно :) Ага, помню ф-цию с похожим названием, авось подойдет - это ж типичное std::мЫшление  :)

Ну или задача поставлена была не полностью.
Ну ладно, давайте "пополнее". Конечно можно генерировать уникальные ID тупенько увеличивая счетчик - и никакие контейнеры не нужны. Но вот хотим сделать иначе - диапазон ID от 100 до 200 (например) использовать для ID параметров/данных определенного типа, другой диапазон - для данных др типа и.т.д. Тут уже счетчиком не отделаться - нужно иметь контейнер созданных ID. И при генерации следующего "заполнять дырку" - вот и имеем задачу стартового поста. Ну и вообще-то "откуда берется задача" - в постановку не входит, товарищи с опытом сами видят откуда :)

Много раз наблюдаю этот эффект: задача (якобы) "непонятна", задаются вопросы. Хорошо, разъясняю, подробнее - так подробнее, здесь секретов нет. НО это никогда ни к чему не ведет :) Вопросы стихают, а интересных ответов/мыслей как не было - так и нету.


Название: Re: Uniquer
Отправлено: RedDog от Июль 07, 2019, 12:19
Процитирую себя:
писать "аналог" БД и заводить индексы, того, чего нет
И собственно в приведенном коде это и было реализовано.
Я не вижу других вариантов кроме как
1. полная беготня по контейнеру от... и ...до с проверками
2. индексация пропущенных или наоборот заюзанных элементов и по этой индексации заполнение нужного контейнера.

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


Название: Re: Uniquer
Отправлено: Igors от Июль 07, 2019, 12:34
Процитирую себя:
писать "аналог" БД и заводить индексы, того, чего нет
И собственно в приведенном коде это и было реализовано.
Я не вижу других вариантов кроме как
1. полная беготня по контейнеру от... и ...до с проверками
2. индексация пропущенных или наоборот заюзанных элементов и по этой индексации заполнение нужного контейнера.

Но второй случай жрет память и при крайних значениях по сложности может вылиться в первый, а то и поболее.
Если Вы говорите о приведенном мной коде - то ни о каких индексах я там не помышлял. И как-то "сгущаете краски" - можно подумать что там нечто ужасное - но ведь это уже успешно решается довольно коротким кодом. Просто мне интересно насколько оптимально это решение и можно ли его улучшить не особо раздувая при этом код - вот об этом я хотел поговорить


Название: Re: Uniquer
Отправлено: RedDog от Июль 07, 2019, 12:44
Если Вы говорите о приведенном мной коде - то ни о каких индексах я там не помышлял. [/quote]
Это чисто вопрос названия, просто в моем текущем проекте подобные решения называются "индексаторами".


Название: Re: Uniquer
Отправлено: ViTech от Июль 07, 2019, 12:57
Просто мне интересно насколько оптимально это решение и можно ли его улучшить не особо раздувая при этом код - вот об этом я хотел поговорить

Тогда стоит указать критерии "оптимальности", а то у каждого они могут оказаться свои. Среди них могут быть: минимум времени разработчика, затраченное на решение задачи, минимум символов в исходном коде решения, не использовать std, использовать такие конструкции С++, чтобы читатели кода мозг сломали и т.п. :).


Название: Re: Uniquer
Отправлено: Old от Июль 07, 2019, 13:30
Тогда стоит указать критерии "оптимальности", а то у каждого они могут оказаться свои. Среди них могут быть: минимум времени разработчика, затраченное на решение задачи, минимум символов в исходном коде решения, не использовать std, использовать такие конструкции С++, чтобы читатели кода мозг сломали и т.п. :).
Еще важнее узнать кто будет оценивать решения. Если сам Igors, то вряд ли найдется решение лучше. :)


Название: Re: Uniquer
Отправлено: Igors от Июль 07, 2019, 13:34
Тогда стоит указать критерии "оптимальности", а то ...
Ну вот, опять танцору что-то мешает :) Есть разные подходы к одной задаче - вот и хотелось бы их увидеть, выбирайте те критерии что Вам по душе. "Вообще без std" бы конечно особо интересно, но разве такие смельчаки найдутся?


Название: Re: Uniquer
Отправлено: ViTech от Июль 07, 2019, 13:42
Ну вот, опять танцору что-то мешает :) Есть разные подходы к одной задаче - вот и хотелось бы их увидеть, выбирайте те критерии что Вам по душе.

Перед критериями оптимальности у меня сначала стоит фильтр: стоит ли вообще заниматься решением какой-то задачи. Так вот на текущий момент данная задача по этому фильтру не проходит, так что извиняйте :).


Название: Re: Uniquer
Отправлено: Igors от Июль 07, 2019, 13:47
Перед критериями оптимальности у меня сначала стоит фильтр: стоит ли вообще заниматься решением какой-то задачи. Так вот на текущий момент данная задача по этому фильтру не проходит, так что извиняйте :).
Увы, привычка "задирать носик" очень быстро приобретается с изучением std :'(
Если Ваш хвильтр стоит "до того" - то чего тогда эфир засорять?


Название: Re: Uniquer
Отправлено: ViTech от Июль 07, 2019, 13:58
Если Ваш хвильтр стоит "до того" - то чего тогда эфир засорять?

Чтоб другие время зря не тратили. Оптимизирую Вашу задачу по времени разработчиков :).


Название: Re: Uniquer
Отправлено: Авварон от Июль 07, 2019, 17:52
Ну задача прямо скажем сформирована фигово. В очередной раз. Да, перечитав сейчас я понимаю, что требуется. Но при первом прочтении (да и последующих) это действительно выглядело как "взять и заполнить ВСЕ дырки в контейнере".
Если 10 человек тебе говорят "пойди проспись" - пойди и проспись=) (с)


Название: Re: Uniquer
Отправлено: Пантер от Июль 07, 2019, 18:14
Igors, на будущее, если ты хочешь, чтобы кто-то за тебя сделал работу, то хотя бы потрудись накидать приемочный тест. Задание сформулировано ужасно.
Вот пример, чтобы ты понял, что от тебя требуется:
Код
C++ (Qt)
int addIfBothPositive(int a, int b)
 
void test() {
   assert (addIfPositive(1, 2) == 3);
   assert (addIfPositive(1, -2) == 1);
   assert (addIfPositive(1, 0) == 1);
   assert (addIfPositive(-1, 5) == -1);
   assert (addIfPositive(-1, -5) == -1);
}
 


Название: Re: Uniquer
Отправлено: Igors от Июль 08, 2019, 11:04
Но при первом прочтении (да и последующих) это действительно выглядело как "взять и заполнить ВСЕ дырки в контейнере".
Да неужели?
Нужна ф-ция которая бы "заполняла дырки" и возвращала заполненное значение не меньше фиксированного заданного min. Напр если min=50 то для контейнера выше ф-ция должна последовательно выдавать
Цитировать
50, 90, 120..9990, 1010..1090. 1110...
Др словами ф-ция вставляет в контейнер наименьшее уникальное значение кратное 10 и >= min
Как видим, речь идет о заполнении строго "по одному", а вовсе не "залить весь массив" - в последнем никакого смысла нет. Меньше надо сборками заниматься :)

Igors, на будущее, если ты хочешь, чтобы кто-то за тебя сделал работу,
Почему Вы полагаете что каждый создающий тему - школота и жадный лох, которому нужно только получить текст под copy/paste? Не надо так плохо думать о людях. Да и как-то неудобно называть этот десяток строк "работой".

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

то хотя бы потрудись накидать приемочный тест. Задание сформулировано ужасно.
Вот пример, чтобы ты понял, что от тебя требуется:
Код
C++ (Qt)
int addIfBothPositive(int a, int b)
 
void test() {
   assert (addIfPositive(1, 2) == 3);
   assert (addIfPositive(1, -2) == 1);
   assert (addIfPositive(1, 0) == 1);
   assert (addIfPositive(-1, 5) == -1);
   assert (addIfPositive(-1, -5) == -1);
}
 
Это что-то типа "TDD"? Ну и что проверяет этот тест, и какая от него польза? По-моему аж никакой  :)


Название: Re: Uniquer
Отправлено: Пантер от Июль 08, 2019, 11:17
Нет, это не TDD.
Польза от него большая, если человек не может сформулировать ТЗ достаточно ясно. Напиши приемочный тест на свою задачу и укажи время выполнения твоего решения, может тогда и будет кому-то интересно покопаться. А так, смысла в твоем топике никакого, только интернет засоряет.


Название: Re: Uniquer
Отправлено: ViTech от Июль 08, 2019, 11:23
Нужна ф-ция которая бы "заполняла дырки" и возвращала заполненное значение не меньше фиксированного заданного min. Напр если min=50 то для контейнера выше ф-ция должна последовательно выдавать
Цитировать
50, 90, 120..9990, 1010..1090. 1110...
Др словами ф-ция вставляет в контейнер наименьшее уникальное значение кратное 10 и >= min
Как видим, речь идет о заполнении строго "по одному", а вовсе не "залить весь массив" - в последнем никакого смысла нет. Меньше надо сборками заниматься :)

Так функция должна последовательно выдавать значения (куда? по одному или скопом? в  результате одного вызова или нескольких?) и/или вставлять значения в контейнер (какой?)?

Это что-то типа "TDD"? Ну и что проверяет этот тест, и какая от него польза? По-моему аж никакой  :)

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


Название: Re: Uniquer
Отправлено: Igors от Июль 09, 2019, 06:08
Так функция должна последовательно выдавать значения (куда? по одному или скопом? в  результате одного вызова или нескольких?)
Общее правило: если что-то не оговорено, то на усмотрение исполнителя. Применим. Почему я не могу запросить не один, а сразу пачку уникальных ID  (они же "заполненные дырки") напр вернув контейнер? Пожалуйста, этого никто не запрещал. Но и не требовал, можно возвращать и единственное значение. Но в любом случае значение(я) должно возвращаться для его использования, иначе смысла нет.
и/или вставлять значения в контейнер (какой?)?
Требуется уникальность, значит, в общем случае, созданное значение должно быть сохранено, так или иначе надо знать какие значения уже имеются. Для их хранения в стартовом посте предлагается контейнер, ни о каком другом речь не шла.

если человек не может сформулировать ТЗ достаточно ясно.
Ход мысли примерно такой "Я не понял - значит сформулировано плохо!". Пример
Цитировать
Руки свисают ниже колен - значит это длинные руки!
Необязательно, это могут быть короткие ноги. Т.е. сформулировано-то нормально, проблемы с "понималкой". Стоило немного подумать - и все бы стало ясно. Не захотели - ну это Ваше дело.


Название: Re: Uniquer
Отправлено: Пантер от Июль 09, 2019, 07:39
>Ход мысли примерно такой "Я не понял - значит сформулировано плохо!"
Как ты можешь видеть выше, не понял задание не только я. Тебе разве не кажется, что пролема не в моей понималке, а в твоем корявом ТЗ?
Если уж ты притащил что-то сюда, то будь добр, прояви уважение к коллегам и сделай все правильно.


Название: Re: Uniquer
Отправлено: Igors от Июль 09, 2019, 12:41
Тебе разве не кажется, что пролема не в моей понималке, а в твоем корявом ТЗ?
Нет, мне совсем так не кажется :) Ладно, кто там чего не понял - это неинтересно, вернемся к теме.

В чем недостаток предложенного решения (пока, увы, одного). Бросается в глаза что хранение организовано туповато, напр { 10, 20, 30, 40, 50.. } Напрашивается хранить не int'ы, а пары (диапазоны) непрерывно возрастающих значений, напр { 10, 50 }. Насколько помню, так Qt хранит selection. Худший случай: непрерывных данных нет, ну расход памяти вдвое больше, переживу. Но т.к. они добавляются подряд, то экономия памяти будет значительна (а заодно и скорость lower_bound). Написать это самому конечно можно, но такое решение следует признать "нетехничным", контейнер диапазонов - задача 100% стандартная и общая, стало быть надо искать готовое решение.

Итак, где же нам хапнуть такой готовый класс?  По этой части я не силен. Ну в дусте наверняка есть - но пока там раскопаешь - проще застрелиться :'( В std - не знаю, когда-то видел std::ranges но оно вроде только С++ 20, да и то ли это - хз

В общем, прошу блеснуть эрудицией и широтой познаний  :)