I have the following simple Graph class, where for each Node, I store a set of outgoing Arcs:
#include <iostream>
#include <vector>
#include <map>
#include <set>
struct Arc {
char label;
int targetNode;
};
struct Graph {
std::vector<int> nodes;
std::map< int, std::set<Arc*> > outgoingArcsPerNode;
};
How can I provide a standard C++ iterator over all the arcs in the graph (order of iteration doesn't matter) that hides how the arcs are stored in the graph?
I would like to use it similar to the following:
int main() {
Graph g;
for (Graph::const_iterator it = g.arcsBegin(); it != g.arcsEnd(); ++it) {
Arc* a = *it;
}
}
I heard of boost::iterator, but I find it confusing. Maybe someone could give a hint how to use it in this case?
If you don't want to use boost, have a look at what iterators must provide : STL documentation.
Otherwise, you may use boost iterator library. See the iterator_facade tutorial which is very close to what you're asking.
Create class which has two iterators inside: one over map and another over set.
Each ++ is applied to set iterator. When it reaches the end, increment map iterator and reinitialize set iterator.
Also you can use boost::iterator_facade - it will not help to implement algorithm of the iteration, but will minimize your effort on making your iterator compatible to STL expectations...
Related
I need a data structure like std::vector or std::list whose elements will be unique. In most of time I will call push_back on it, sometimes maybe erase. When I insert an element which is already there, I need to be notified either by some boolean or exception.
And the most important property it should have: the order of insertions. Each time I iterate over it, it should return elements in the order they were inserted.
We can think other way: a queue which guarantees the uniqueness of elements. But I don't want to pop elements, instead I want to iterate over them just like we do for vector or list.
What is the best data structure for my needs?
You can use a std::set
It will return a pair pair<iterator,bool> when the insert method is called. The bool in the pair is false when the element already exists in the set (the element won't be added in that case).
Use a struct with a regular std::vector and a std::set.
When you push, check the set for existence of the element. When you need to iterate, iterate over the vector. If you need to erase from the vector, also erase from the set.
Basically, use the set as an aside, only for fast "presence of an element" check.
// either make your class a template or use a fixed type of element
class unique_vector
{
public:
// implement the various operator you need like operator[]
// alternatively, consider inheriting from std::vector
private:
std::set<T> m_set; // fast lookup for existence of elements
std::vector<T> m_vector; // vector of elements
};
I would prefer using std::unordered_set to stores existing elements in a std::vector and it has faster lookup time of O(1), while the lookup time of std::set is O(logn).
You can use Boost.MultiIndex for this:
Live On Coliru
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
using namespace boost::multi_index;
template<typename T>
using unique_list=multi_index_container<
T,
indexed_by<
sequenced<>,
hashed_unique<identity<T>>
>
>;
#include <iostream>
int main()
{
unique_list<int> l;
auto print=[&](){
const char* comma="";
for(const auto& x:l){
std::cout<<comma<<x;
comma=",";
}
std::cout<<"\n";
};
l.push_back(0);
l.push_back(1);
l.push_back(2);
l.push_back(0);
l.push_back(2);
l.push_back(4);
print();
}
Output
0,1,2,4
Full disclosure, this may be a hammer and nail situation trying to use STL algorithms when none are needed. I have seen a reappearing pattern in some C++14 code I am working with. We have a container that we iterate through, and if the current element matches some condition, then we copy one of the elements fields to another container.
The pattern is something like:
for (auto it = std::begin(foo); it!=std::end(foo); ++it){
auto x = it->Some_member;
// Note, the check usually uses the field would add to the new container.
if(f(x) && g(x)){
bar.emplace_back(x);
}
}
The idea is almost an accumulate where the function being applied does not always return a value. I can only think of a solutions that either
Require a function for accessing the member your want to accumulate and another function for checking the condition. i.e How to combine std::copy_if and std::transform?
Are worse then the thing I want to replace.
Is this even a good idea?
A quite general solution to your issue would be the following (working example):
#include <iostream>
#include <vector>
using namespace std;
template<typename It, typename MemberType, typename Cond, typename Do>
void process_filtered(It begin, It end, MemberType iterator_traits<It>::value_type::*ptr, Cond condition, Do process)
{
for(It it = begin; it != end; ++it)
{
if(condition((*it).*ptr))
{
process((*it).*ptr);
}
}
}
struct Data
{
int x;
int y;
};
int main()
{
// thanks to iterator_traits, vector could also be an array;
// kudos to #Yakk-AdamNevraumont
vector<Data> lines{{1,2},{4,3},{5,6}};
// filter even numbers from Data::x and output them
process_filtered(std::begin(lines), std::end(lines), &Data::x, [](int n){return n % 2 == 0;}, [](int n){cout << n;});
// output is 4, the only x value that is even
return 0;
}
It does not use STL, that is right, but you merely pass an iterator pair, the member to lookup and two lambdas/functions to it that will first filter and second use the filtered output, respectively.
I like your general solutions but here you do not need to have a lambda that extracts the corresponding attribute.
Clearly, the code can be refined to work with const_iterator but for a general idea, I think, it should be helpful. You could also extend it to have a member function that returns a member attribute instead of a direct member attribute pointer, if you'd like to use this method for encapsulated classes.
Sure. There are a bunch of approaches.
Find a library with transform_if, like boost.
Find a library with transform_range, which takes a transformation and range or container and returns a range with the value transformed. Compose this with copy_if.
Find a library with filter_range like the above. Now, use std::transform with your filtered range.
Find one with both, and compose filtering and transforming in the appropriate order. Now your problem is just copying (std::copy or whatever).
Write your own back-inserter wrapper that transforms while inserting. Use that with std::copy_if.
Write your own range adapters, like 2 3 and/or 4.
Write transform_if.
First of all, what is the main difference between them?
The only thing i've found is that unordered_set has no operator [].
How should i access an element in unordered_set, since there is no []?
Which container is using random access to memory(or both)?
And which one of them faster in any sense or using less memory?
They are nearly identical. unordered_set only contains keys, and no values. There is no mapping from a key to a value, so no need for an operator[]. unordered_map maps a key to a value.
You can use the various find methods within unordered_set to locate things.
you can use iterators to access elements.
unordered_set <string> u{
"Dog",
"Cat",
"Rat",
"Parrot",
"bee"
};
for(auto& s:u){
cout << s << ' ';
}
unordered_set<string>::const_iterator point = u.find("bee");
How should I access an element in unordered_set (C++17)?
In C++ 17 a new function extract is added to unordered_set.
Specially, this is the only way to take move only object out of the set.
https://en.cppreference.com/w/cpp/container/unordered_set/extract
For example if you want third element of your unordered set.
Advance the iterator
std::advance(it,2);
Then extarct the value
s.extract(it).value();
Here is the complete code. try on any C++17 compiler.
#include <iostream>
#include <string>
#include <unordered_set>
#include <iterator>
int main()
{
//CREATE AN OBJECT
std::unordered_set<std::string> s;
//INSERT DATA
s.insert("aee");
s.insert("bee");
s.insert("cee");
s.insert("dee");
//NEED TO INCLUDE "iterator" HEADER TO USE "std::advance"
auto it = s.begin();
std::advance(it,2);
//USING EXTRACT
std::string sval = s.extract(it).value();
std::cout<<sval;
}
Note: if queried for out of bound index, nothing happens. No result.
Try changing your code
//ONLY FOUR ELEMENTS
std::advance(it,8);
//USING EXTRACT
std::string sval = s.extract(it).value();
I'd like to delete some element out of a boost multi-index container by erasing iterators while visiting the collection.
What I am not sure about is if any iterator invalidation is involved and whether my code below would invalidate firstand last iterators.
If the code below is incorrect, which is the best way considering the specific index (ordered_unique) below?
#include <iostream>
#include <stdint.h>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/key_extractors.hpp>
#include <boost/shared_ptr.hpp>
using namespace std;
class MyClass{
public:
MyClass(int32_t id) : id_(id) {}
int32_t id() const
{ return id_; }
private:
int32_t id_;
};
typedef boost::shared_ptr<MyClass> MyClass_ptr;
typedef boost::multi_index_container<
MyClass_ptr,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<
boost::multi_index::const_mem_fun<MyClass,int32_t,&MyClass::id>
>
>
> Coll;
int main() {
Coll coll;
// ..insert some entries 'coll.insert(MyClass_ptr(new MyClass(12)));'
Coll::iterator first = coll.begin();
Coll::iterator last = coll.end();
while(first != last) {
if((*first)->id() == 3)
coll.erase(first++);
else
++first;
}
}
The reason that erase for containers returns an iterator is to use that result:
first = coll.erase(first);
Then you don't have to worry about how the underlying implementation handles erase or whether it shifts elements around. (In a vector, for instance, your code would've skipped an element in your iteration) However, the documentation does state that:
It is tempting to see random access indices as an analogue of std::vector for use in Boost.MultiIndex, but this metaphor can be misleading, as both constructs, though similar in many respects, show important semantic differences. An advantage of random access indices is that their iterators, as well as references to their elements, are stable, that is, they remain valid after any insertions or deletions.
Still, just seeing coll.erase(first++) is a flag for me, so prefer to do it the other way.
I have been going through the boost::range library and noticed boost::range_iterator and boost::iterator_range. I am confused with these terms here. Could anyone please explain what is the difference between two and when to use what? Also, it would be nice if you can point me to sample examples where the boost range library is used to know more about it apart from the documentation.
Could anyone please explain what is the difference between two and when to use what?
range_iterator is used for get type of range iterator in following way:
range_iterator< SomeRange >::type
It simillar in something to std::iterator_traits. For instance, you may get value type from iterator:
std::iterator_traits<int*>::value_type
iterator_range is bridge between ranges and iterators. For instance - you have pair of iterators, and you want pass them to algorithm which only accepts ranges. In that case you can wrap your iterators into range, using iterator_range. Or better - make_iterator_range - it will help to deduce types (like std::make_pair does):
make_iterator_range(iterator1,iterator2)
returns range.
Consider following example:
live demo
#include <boost/range/iterator_range.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/iterator.hpp>
#include <typeinfo>
#include <iostream>
#include <ostream>
using namespace boost;
using namespace std;
struct print
{
template<typename T>
void operator()(const T &t) const
{
cout << t << " ";
}
};
int main()
{
typedef int Array[20];
cout << typeid( range_iterator<Array>::type ).name() << endl;
Array arr={11,22,33,44,55,66,77,88};
boost::for_each( make_iterator_range(arr,arr+5) ,print());
}
Also, it would be nice if you can point me to sample examples where the boost range library is used to know more about it apart from the documentation
For quick summary - check this slides
Generally, you will not use boost::range_iterator directly, as it is a template metafunction which takes the range given (regardless of the type of the range), and returns the type of it's begin()/end() methods.
boost::iterator_range is used to create a new range from a pair of pre-existing iterators. This you will be more likely to use, usually when taking code that is still iterator based and using that to convert to a range.