I want to implement something similar to std::stable_partition but for forward_list of c++11.
The stl version requires bidirectional iterators, however by utilizing container specific methods I believe I can get the same outcome effeciently.
Example declaration :
template <typename T, typename UnaryPredicate>
void stable_partition(std::forward_list<T>& list, UnaryPredicate p);
(while possible to add begin and end iterators, I omitted them for brevity. The same for returning the partition point )
I already worked out the algorithm to accomplish this on my own list type, but I have troubles implementing it in stl.
The key method appears to be splice_after. Other methods require memory allocations and copying elements.
Algorithm sketch :
create a new empty list. It will hold all elements p returns true on.
loop over the target list, add items to the true list in accordance to invoking p.
concat the true list to the beginning of the target list.
With proper coding this should be linear time (all operations inside the loop can be done in constant time) and without extra memory allocation or copying.
I am trying to implement the second step using splice_after, but I end up either concating the wrong element or invalidating my iterators.
The question:
What is the correct use of splice_after, so that I avoid
mixing iterators between lists and insert the correct elements?
First Attempt (how I hoped it works):
template <typename T, typename UnaryPredicate>
void stable_partition(std::forward_list<T>& list, UnaryPredicate p)
{
std::forward_list<T> positives;
auto positives_iter = positives.before_begin();
for (auto iter = list.begin(); iter != list.end(); ++iter)
{
if (p(*iter))
positives.splice_after(positives_iter, list, iter);
}
list.splice_after(list.before_begin(), positives);
}
Unfortunately this has at least one major flaw: splice_after inserts after iter, and the wrong element is inserted.
Also, when the element is moved to the other list, incrementing iter now traverses the wrong list.
Having to maintain the preceding iterators for std::forward_list::splice_after makes it a bit trickier, but still pretty short:
template<class T, class UnaryPredicate>
std::array<std::forward_list<T>, 2>
stable_partition(std::forward_list<T>& list, UnaryPredicate p) {
std::array<std::forward_list<T>, 2> r;
decltype(r[0].before_begin()) pos[2] = {r[0].before_begin(), r[1].before_begin()};
for(auto i = list.before_begin(), ni = i, e = list.end(); ++ni != e; ni = i) {
bool idx = p(*ni);
auto& p = pos[idx];
r[idx].splice_after(p, list, i);
++p;
}
return r;
}
Usage example:
template<class T>
void print(std::forward_list<T> const& list) {
for(auto const& e : list)
std::cout << e << ' ';
std::cout << '\n';
}
int main() {
std::forward_list<int> l{0,1,2,3,4,5,6};
print(l);
// Partition into even and odd elements.
auto p = stable_partition(l, [](auto e) { return e % 2; });
print(p[0]); // Even elements.
print(p[1]); // Odd elements.
}
Related
I have two std::maps:
std::map<int,int> map1;
std::map<int,int> map2;
I need to iterate over one backwards and the other forwards (because that is the pattern of data access). Whilst iterating I would like to be able to erase elements continue iterating.
I would like to use the same method.
I have seen examples using templates showing how to iterate bidirectionally, but doesn't demonstrate erasing elements (and this is important because erase() only works with forward iterators):
Iterating over a container bidirectionally
and I have seen reverse_iterator examples which erase, but they aren't bidirectional:
How to call erase with a reverse iterator using a for loop
but I would like to iterate bidirectionally and erase?
You can write a function for a std::map, std::set or std::list:
template<typename Cont, typename Pred>
void bidir_remove_if( Cont &c, Pred p, bool forward )
{
auto b = c.begin();
auto e = c.end();
while( b != e ) {
auto it = forward ? b++ : --e;
if( p(*it) ) {
auto end = b == e;
( forward ? it : e ) = c.erase( it );
if( end ) break;
}
}
}
live example
note - you cannot use this function for std::vector due to invalidation of iterators (and you should not as you better use erase-remove idiom for it).
I want to use a circular list.
Short of implementing my own (like this person did) what are my options?
Specifically what I want to do is iterate over a list of objects. When my iterator reaches the end of the list, it should automatically return to the beginning. (Yes, I realize this could be dangerous.)
See Vladimir's definition of a circular_iterator: "A circular_iterator will never be equal with CircularList::end(), thus you can always dereference this iterator."
There's no standard circular list.
However, there is a circular buffer in Boost, which might be helpful.
If you don't need anything fancy, you might consider just using a vector and accessing the elements with an index. You can just mod your index with the size of the vector to achieve much the same thing as a circular list.
If you want something looking like an iterator you can roll your own, looking something like
template <class baseIter>
class circularIterator {
private:
baseIter cur;
baseIter begin;
baseIter end;
public:
circularIterator(baseIter b, baseIter e, baseIter c=b)
:cur(i), begin(b), end(e) {}
baseIter & operator ++(void) {++cur; if(cur == end) {cur = begin;}}
};
(Other iterator operations left as exercise to reader).
list<int>::iterator circularNext(list<int> &l, list<int>::iterator &it)
{
return std::next(it) == l.end() ? l.begin() : std::next(it);
}
In addition to #captain-segfault and #mahmoud-khaled's iterator-focused answers, you can also use std::list as a circular list by altering what you do to retrieve elements from it. Use splice to move one end of the list to the other end as you process it.
template <typename T>
T & circularFront(std::list<T> & l)
{
l.splice(l.end(), l, l.begin());
return l.back();
}
template <typename T>
T & circularBack(std::list<T> & l)
{
l.splice(l.begin(), l, l.rbegin());
return l.front();
}
I found this solition. Works fine for me.
std::list<int> List{ 1,2,3,4,5,6 };
auto it = List.end();
it--;
it._Ptr->_Next = List.begin()._Ptr; // Next Node of the last elemen is now first elemen of the List
List.begin()._Ptr->_Prev = it._Ptr; // Prev Node of the first element is now Last node
for (int num : List)
{
std::cout << num << '\n';
}
In this case we will loop indefinitely. Should work backward too.
Output
1
2
3
4
5
6
1
2
3
4
5
6
1
.
.
I have a Visual Studio 2008 C++03 application where I have two standard containers. I would like to remove from one container all of the items that are present in the other container (the intersection of the sets).
something like this:
std::vector< int > items = /* 1, 2, 3, 4, 5, 6, 7 */;
std::set< int > items_to_remove = /* 2, 4, 5*/;
std::some_algorithm( items.begin, items.end(), items_to_remove.begin(), items_to_remove.end() );
assert( items == /* 1, 3, 6, 7 */ )
Is there an existing algorithm or pattern that will do this or do I need to roll my own?
Thanks
Try with:
items.erase(
std::remove_if(
items.begin(), items.end()
, std::bind1st(
std::mem_fun( &std::set< int >::count )
, items_to_remove
)
)
, items.end()
);
std::remove(_if) doesn't actually remove anything, since it works with iterators and not containers. What it does is reorder the elements to be removed at the end of the range, and returns an iterator to the new end of the container. You then call erase to actually remove from the container all of the elements past the new end.
Update: If I recall correctly, binding to a member function of a component of the standard library is not standard C++, as implementations are allowed to add default parameters to the function. You'd be safer by creating your own function or function-object predicate that checks whether the element is contained in the set of items to remove.
Personally, I prefer to create small helpers for this (that I reuse heavily).
template <typename Container>
class InPredicate {
public:
InPredicate(Container const& c): _c(c) {}
template <typename U>
bool operator()(U const& u) {
return std::find(_c.begin(), _c.end(), u) != _c.end();
}
private:
Container const& _c;
};
// Typical builder for automatic type deduction
template <typename Container>
InPredicate<Container> in(Container const& c) {
return InPredicate<Container>(c);
}
This also helps to have a true erase_if algorithm
template <typename Container, typename Predicate>
void erase_if(Container& c, Predicate p) {
c.erase(std::remove_if(c.begin(), c.end(), p), c.end());
}
And then:
erase_if(items, in(items_to_remove));
which is pretty readable :)
One more solution:
There is standard provided algorithm set_difference which can be used for this.
But it requires extra container to hold the result. I personally prefer to do it in-place.
std::vector< int > items;
//say items = [1,2,3,4,5,6,7,8,9]
std::set<int>items_to_remove;
//say items_to_remove = <2,4,5>
std::vector<int>result(items.size()); //as this algorithm uses output
//iterator not inserter iterator for result.
std::vector<int>::iterator new_end = std::set_difference(items.begin(),
items.end(),items_to_remove.begin(),items_to_remove.end(),result.begin());
result.erase(new_end,result.end()); // to erase unwanted elements at the
// end.
You can use std::erase in combination with std::remove for this. There is a C++ idiom called the Erase - Remove idiom, which is going to help you accomplish this.
Assuming you have two sets, A and B, and you want to remove from B, the intersection, I, of (A,B) such that I = A^B, your final results will be:
A (left intact)
B' = B-I
Full theory:
http://math.comsci.us/sets/difference.html
This is quite simple.
Create and populate A and B
Create a third intermediate vector, I
Copy the contents of B into I
For each element a_j of A, which contains j elements, search I for the element a_j; If the element is found in I, remove it
Finally, the code to remove an individual element can be found here:
How do I remove an item from a stl vector with a certain value?
And the code to search for an item is here:
How to find if an item is present in a std::vector?
Good luck!
Here's a more "hands-on" in-place method that doesn't require fancy functions nor do the vectors need to be sorted:
#include <vector>
template <class TYPE>
void remove_intersection(std::vector<TYPE> &items, const std::vector<TYPE> &items_to_remove)
{
for (int i = 0; i < (int)items_to_remove.size(); i++) {
for (int j = 0; j < (int)items.size(); j++) {
if (items_to_remove[i] == items[j]) {
items.erase(items.begin() + j);
j--;//Roll back the iterator to prevent skipping over
}
}
}
}
If you know that the multiplicity in each set is 1 (not a multiset), then you can actually replace the j--; line with a break; for better performance.
I'm a C programmer and trying to get better at C++. I want to implement a permutation function (without using the STL algorithms). I came up with the following algorithm (out of my C way of thinking), but
a) it crashes for k > 2 (I suppose because the element that the iterator
points to, gets deleted, is inserted back and then incremented).
b) erase/insert operation seem unnecessary.
How would the C++ experts amongst you implement it?
template <class T>
class Ordering {
public:
Ordering(int n);
int combination(int k);
int permutation(int k);
private:
set<T> elements;
vector<T> order;
}
template <class T>
int Ordering<T>::permutation (int k) {
if (k > elements.size()) {
return 0;
}
if (k == 0) {
printOrder();
return 1;
}
int count = 0;
for (typename set<T>::iterator it = elements.begin();
it != elements.end();
it++
)
{
order[k-1] = *it;
elements.erase(*it);
count += permutation(k-1);
elements.insert(*it);
}
return count;
}
The problem is in your iteration over the elements set. You try to increment an iterator which you have removed. That cannot work.
If you insist in using this approach, you must store the successor of it, before calling set::erase. That means you have to move the incrementation part of your for loop into the loop.
Like this:
for (typename set<T>::iterator it = elements.begin();
it != elements.end();
/* nothing here */
)
{
order[k-1] = *it;
typename set<T>::iterator next = it;
++next;
elements.erase(*it);
count += permutation(k-1);
elements.insert(order[k-1]);
it = next;
}
Edit: One possible way of temporarily "removing" objects from your set would be to have a std::set<std::pair<T,bool>> and simply write it->second = false and afterwards it->second = true. Then, while iterating, you can skip entries where the second value is false. This adds a bit of an overhead since you have to do a lot more work while descending. But inserting+removing elements adds a logarithmic overhead every time, which is probably worse.
If you used a (custom) linked list (perhaps you can even get std::list to do that) you could very inexpensively remove and re-insert objects.
I want to make a function which moves items from one STL list to another if they match a certain condition.
This code is not the way to do it. The iterator will most likely be invalidated by the erase() function and cause a problem:
for(std::list<MyClass>::iterator it = myList.begin(); it != myList.end(); it++)
{
if(myCondition(*it))
{
myOtherList.push_back(*it);
myList.erase(it);
}
}
So can anyone suggest a better way to do this ?
Erase returns an iterator pointing to the element after the erased one:
std::list<MyClass>::iterator it = myList.begin();
while (it != myList.end())
{
if(myCondition(*it))
{
myOtherList.push_back(*it);
it = myList.erase(it);
}
else
{
++it;
}
}
STL lists have an interesting feature: the splice() method lets you destructively move elements from one list to another.
splice() operates in constant time, and doesn't copy the elements or perform any free store allocations/deallocations. Note that both lists must be of the same type, and they must be separate list instances (not two references to the same list).
Here's an example of how you could use splice():
for(std::list<MyClass>::iterator it = myList.begin(); it != myList.end(); ) {
if(myCondition(*it)) {
std::list<MyClass>::iterator oldIt = it++;
myOtherList.splice(myOtherList.end(), myList, oldIt);
} else {
++it;
}
}
Solution 1
template<typename Fwd, typename Out, typename Operation>
Fwd move_if(Fwd first, Fwd last, Out result, Operation op)
{
Fwd swap_pos = first;
for( ; first != last; ++first ) {
if( !op(*first) ) *swap_pos++ = *first;
else *result++ = *first;
}
return swap_pos;
}
The idea is simple. What you want to do is remove elements from one container and place them in another if a predicate is true. So take the code of the std::remove() algorithm, which already does the remove part, and adapt it to your extra needs. In the code above I added the else line to copy the element when the predicate is true.
Notice that because we use the std::remove() code, the algorithm doesn't actually shrink the input container. It does return the updated end iterator of the input container though, so you can just use that and disregard the extra elements. Use the erase-remove idiom if you really want to shrink the input container.
Solution 2
template<typename Bidi, typename Out, typename Operation>
Bidi move_if(Bidi first, Bidi last, Out result, Operation op)
{
Bidi new_end = partition(first, last, not1(op));
copy(new_end, last, result);
return new_end;
}
The second approach uses the STL to implement the algorithm. I personally find it more readable than the first solution, but it has two drawbacks: First, it requires the more-powerful bidirectional iterators for the input container, rather than the forward iterators we used in the first solution. Second, and this is may or may not be an issue for you, the containers are not guaranteed to have the same ordering as before the call to std::partition(). If you wish to maintain the ordering, replace that call with a call to std::stable_partition(). std::stable_partition() might be slightly slower, but it has the same runtime complexity as std::partition().
Either Way: Calling the Function
list<int>::iterator p = move_if(l1.begin(), l1.end(),
back_inserter(l2),
bind2nd(less<int>(), 3));
Final Remarks
While writing the code I encountered a dilemma: what should the move_if() algorithm return? On the one hand the algorithm should return an iterator pointing to the new end position of the input container, so the caller can use the erase-remove idiom to shrink the container. But on the other hand the algorithm should return the position of the end of the result container, because otherwise it could be expensive for the caller to find it. In the first solution the result iterator points to this position when the algorithm ends, while in the second solution it is the iterator returned by std::copy() that points to this position. I could return a pair of iterators, but for the sake of making things simple I just return one of the iterators.
std::list<MyClass>::iterator endMatching =
partition(myList.begin(), myList.end(), myCondition);
myOtherList.splice(myOtherList.begin(), myList, endMatching, myList.end());
Note that partition() gives you enough to discriminate matching objects from non matching ones.
(list::splice() is cheap however)
See the following code on a concrete case inspired from
Now to remove elements that match a predicate?
#include <iostream>
#include <iterator>
#include <list>
#include <string>
#include <algorithm>
#include <functional>
using namespace std;
class CPred : public unary_function<string, bool>
{
public:
CPred(const string& arString)
:mString(arString)
{
}
bool operator()(const string& arString) const
{
return (arString.find(mString) == std::string::npos);
}
private:
string mString;
};
int main()
{
list<string> Strings;
Strings.push_back("213");
Strings.push_back("145");
Strings.push_back("ABC");
Strings.push_back("167");
Strings.push_back("DEF");
cout << "Original list" << endl;
copy(Strings.begin(), Strings.end(),ostream_iterator<string>(cout,"\n"));
CPred Pred("1");
// Linear. Exactly last - first applications of pred, and at most (last - first)/2 swaps.
list<string>::iterator end1 =
partition(Strings.begin(), Strings.end(), Pred);
list<string> NotMatching;
// This function is constant time.
NotMatching.splice(NotMatching.begin(),Strings, Strings.begin(), end1);
cout << "Elements matching with 1" << endl;
copy(Strings.begin(), Strings.end(), ostream_iterator<string>(cout,"\n"));
cout << "Elements not matching with 1" << endl;
copy(NotMatching.begin(), NotMatching.end(), ostream_iterator<string>(cout,"\n"));
return 0;
}
Another attempt:
for(std::list<MyClass>::iterator it = myList.begin(); it != myList.end; ) {
std::list<MyClass>::iterator eraseiter = it;
++it;
if(myCondition(*eraseiter)) {
myOtherList.push_back(*eraseiter);
myList.erase(eraseiter);
}
}
template <typename ForwardIterator, typename OutputIterator, typename Predicate>
void splice_if(ForwardIterator begin, ForwardIterator end, OutputIterator out, Predicate pred)
{
ForwardIterator it = begin;
while( it != end )
{
if( pred(*it) )
{
*begin++ = *out++ = *it;
}
++it;
}
return begin;
}
myList.erase(
splice_if( myList.begin(), myList.end(), back_inserter(myOutputList),
myCondition
),
myList.end()
)