ulidtko
01.08.2012 13:22
std::vector<int> vec;
//...
vec.erase(std::remove(vec.begin(), vec.end(), value));
Форденька, ну за что, за что мне весь этот пиздец //-___-\\
Compare to:
>>> ints = [1,2,3]
>>> ints.remove(2)
>>> ints
[1, 3]
Причем ты мудак и сделал все неправильно.
vec.erase (std::remove (...), vec.end ()); для случая, когда больше одного значения удовлетворяет.
лол, плюсую
да-да, про пример в http://en.cppreference.com/w/cpp/algorit... я вообще молчу, настолько охуел от него
А что?
что с ним?
как это работает? std::remove возвращает итератор на что, на элементы, равные value? каким хуем они тогда оказываются в конце контейнера? >_<
remove перемещает элементы, удовлетворяющие предикату, в конец контейнера, и возвращает итератор на первый такой перемещенный элемент.
Ты ж сам ссылку привел на cppreference. Вникай в тамошний код до просветления :3
или std::remove возвращает итераторы типа как бы не по очереди, а сначала-все-остальные-потом-подходящие-по-критерию по очереди?
std::remove тасует элементы, убирая в конец все, что "удаляется", возвращает итератор, указывающий на конец оставшихся элементов. erase-у передается он, как начало и старый конец, как конец. За счет этого стирается сразу блок.
Че блядь.
как он их перемещает? он не может менять контейнер же.
Может.
С чего бы это?
ага, ну я так и понял. И ВНЕЗАПНО .end() этого итератора совпадает с .end() нашего исходного итератора, вообще охуеть блядь.
» И ВНЕЗАПНО .end() этого итератора совпадает с .end() нашего исходного итератора, вообще охуеть блядь
ШТО ?
> end() итератора
Чтоблядь.
Хотя, возможно, ты имел ввиду, что если элементов не найдется, то будет vec.erase (end, end); И что тебя смущает?
Олсо, почему-то хочется запостить сюда это → :3
Ваганизация треда.
Собственно, достаточно просто помнить, что STL работает с полуоткрытыми интервалами, и удаление [end; end) ничего не меняет, очевидно.
в самом тупом и простом случае не меняет. И собственно нужный эффект не этим достигается, не свапаньем элементов в контейнере, а очередностью возврата итераторов.
> очередностью возврата итераторов
Блядь што.
Итератор возвращается там один раз. Нет тут никаких yield и всего такого.
не слушай этих плюсоблядей. Они люди потерянные для общества. Куда проще сделать просто remove [элемент]. Правда не понятно, как сделать удаление элементов только в части массива, а не во всем, но похуй. Питону это и не надо. Так что все ты правильно возмущаешься
нет, я не об этом. std::remove возвращает что? некий свой итератор со своим поведением. Который не совпадает с итератором, возвращаемым vec.begin(). Почему тогда его специальное значение, означающее конец итерирования, совпадает с vec.end()? Это ведь разные итераторы.
Хуйню сказал, бро. Покури Possible implementation, представляя, что там не итераторы, а указатели.
гагага, а yield с помощью ++ не хочешь?
Щто.
почему это у него свое поведение ? О_О
>ForwardIterator result = first; С этого места же видно, что это итератор того же типа, а значит и поведения, что и переданы при вызове.
> Правда не понятно, как сделать удаление элементов только в части массива, а не во всем
чего непонятного-то, навешиваешь какой-нибудь range adaptor (например, самый простой slice syntax в питоне) и удаляешь, элементарно.
ой ёлки, открой для себя слайсы.
потому что он после ++ возвращает не то, что возвращает результат vec.begin().
я не вижу, где и как в Possible implementations происходит перемещение заматченых элементов в конец.
Нихуя не понял, все три итератора vec.begin(), vec.end() и внутренний result указывают на одну коллецию! Но на разные ее позиции. Почему это разное поведение ?
Здесь: if (!p(*first)) {
*result++ = *first;
}
Нет, ну правда, представь, что это сишка и ForwardIterator ~ char * какой-нибудь.
да, вчитался уже. Оно перезаписывает контейнер, сдвигая элементы поверх заматченных. В конце остается мусор. Из функции возвращается указатель на начало мусора.
Пиздец-пиздец, нахуй так жить, посоны.
Вот сейчас все верно.
— не прошло и сорока коментов. Блюю.
Питонируешь.
уже сам факт того, что выставляемые интерфейсы сложно понять, если не смотреть в possible implementation, говорит о крайне хуевом дизайне. Это если не говорить о том, что эти интерфейсы вообще излишни как абстракции, поскольку по всей стандартной библиотеке подразумевают единственный способ реализации.
если бы. Питонировал бы с радостью (items.remove(item)), но приходится жрать говно. :(
Все претензии Степанову, он художник.
» Это если не говорить о том, что эти интерфейсы вообще излишни как абстракции, поскольку по всей стандартной библиотеке подразумевают единственный способ реализации.
Нет, не подразумевают.
подразумевают. Посмотри на требования по сложности к любому из стандартных контейнеров, они прямо кричат Я ДЕРЕВО, Я СПИСОК, Я ХЕШТАБЛИЦА этц.
Посмотри, как сделано std::copy в студии, например.
то есть, не Я ДЕРЕВО, а ЭТОТ (оче дохуя абстрактный) КОНТЕЙНЕР НЕЛЬЗЯ РЕАЛИЗОВАТЬ ИНАЧЕ ЧЕМ СБАЛАНСИРОВАННЫМ ДЕРЕВОМ.
Например. Или любой из тех же стандартных алгоритмов, лол. Они «абстрагируют» в среднем 5-10 строчек кода, которые просто невозможно написать иначе, не нарушив требования интерфейса. Говно это, а не абстракции.
тот же unordered_set как только не реализовывали, что EA, что в boost, что в STLPort. А уж про то, что алгоритмы неспециализированы — тут совсем мимо. Смотри std::copy, смотри std::fill. Кроме того, можно тот же find прокрутить быстрее, если распознать на входе итераторы от set, например. Вызвав бинарный поиск у самого set вместо тупой линейщинки.
посмотрел std::copy, std::fill, std::transform, везде узнаваемые циклы. В точности такие, как и подразумевает спецификация. Ну, плюс, дебажный range checking да специализации^W function overloads для char*, unsigned char*.
template<class _FwdIt, class _Ty> inline
void __CLRCALL_OR_CDECL _Fill(_FwdIt _First, _FwdIt _Last, const _Ty& _Val)
{ // copy _Val through [_First, _Last)
_DEBUG_RANGE(_First, _Last);
for (; _First != _Last; ++_First)
*_First = _Val;
}
inline void __CLRCALL_OR_CDECL _Fill(_Out_capcount_x_(_Last-_First) char *_First,
_In_opt_ char *_Last, int _Val)
{ // copy char _Val through [_First, _Last)
_DEBUG_RANGE(_First, _Last);
::memset(_First, _Val, _Last — _First);
}
//...
tell me moar про реализации unordered_set
Циклы ок, но я как раз про версии для примитивов и дебажные кишки. Это уже не описано в стандарте, но и не нарушает его!
Это поискать надо, вечерком, думаю, кину.
с итераторами в виде генераторов (а не указателей) свободы реализации было бы way more, как мне кажется.
Но я вроде уже начинаю понимать tradeoff между лоулевельностью-байтоебством и абстрактностью-удобством использования. Наверное. Хоть и не согласен с ним. Не должно его здесь быть. Получать производительность можно без жертв в удобстве.
Ну да, это просто компромисс. В Qt есть Java-style итераторы, если хочется что-то другое еще.
Вот тут про старые реализации хэширующих контейнеров, обрати внимание:
http://attractivechaos.wordpress.com/200...
"Open addressing vs. chaining hash. Khash and google hash implement open addressing hash while the remaining implement chaining hash. In open addressing hash, the size of each bucket equals the size of a key plus 0.25 byte. Google sparsehash further compresses unused bucket to 1 bit, achieving high memory efficiency. In chaining hash, the memory overhead of each bucket is at least 4 bytes on 32bit machines, or 8 bytes on 64bit machines. However, chaining hash is less affected when the hash table is nearly full. In practice, both open addressing and chaining hash occupy similar memory under similar speed. Khash takes less peak memory mainly due to its advanced technique in rehashing which reduces memory usage. So far as speed is concerned, chaining hash may have fewer comparison between keys. We can see this from the fact that the speed of chaining hash approaches that of open addressing hash on string keys but much slower on integer keys."
И опять же, в стандарте не сказано, использовать ли открытую адресацию или цепочки для разрешения коллизий. Правда, насколько я видел, в студии цепочками сделано. В GCC не видал.
я бы не стал использовать метод из питона нигде, кроме скрипткид-скриптов
проиграл
почему?
Потому что питон негде использовать, кроме как в 10-строчных скриптах.
не эффективно, лучше запилить решение на другой структуре данных или пересмотреть работу алгоритма :cf:
штосука, черезчур толсто!
а ты так сразу и повёлся. ЛОХ
я серьёзно, приведи мне пример, где данный способ будет лучшим
лучшим чем что?
чем плюсы)))
items.erase(std::remove(items.begin(), items.end(), value));
VS
items.remove(value)
привёл.
ну что, вековая проблема решена — плюсы сосут у питона. Расходимся