The following code doesn't compile.
The line with pair is giving the error. Is there some other way to access the data or is this
way correct??
unordered_map<int,int> hm;
unordered_map<int,int>::iterator it;
it=find(hm.begin(),hm.end(),x+c);
if (it!=hm.end())
{
bNotFound = false;
pair<int,int> p = *it;
ind = p.second;
}
Sometimes the compiler does a lousy job with the error messages. Your problem is the find algorithm.
unordered_map & map have their own find, which take the key as argument and returns an iterator. The algorithm is looking for the key:
auto it = hm.find(key);
if (it != hm.end())
{
// ...
}
The global find algorithm takes a search interval and a value as input. But it works with any container that meets some iterators constrains. In the case of a map the value is not the key, as in the unordered_map::find but the (key, value) pair. The algorithm is looking for the (key, value) pair. You can declare your target value and use it like this:
unordered_map<int, int>::value_type target{ key, value };
auto it = find(hm.begin(), hm.end(), target);
if (it != hm.end())
{
// ...
}
Related
So I have the following map parseTable
std::map<std::pair<Symbol, Symbol>, list<Symbol> > parseTable;
I am confused on how to access to the list value if I have my map initialized this way:
std::map<std::pair<Symbol, Symbol>, list<Symbol> > parseTable = {
{{Symbol::Input, Symbol::OpenPar}, {Symbol::Expr, Symbol::Semicolon, Symbol::InputP}},
{{Symbol::Input, Symbol::Ident}, {Symbol::Expr, Symbol::Semicolon, Symbol::InputP}},
{{Symbol::Input, Symbol::Number}, {Symbol::Expr, Symbol::Semicolon, Symbol::InputP}}
};
I want to access to each of the values of my list individually when I use the find() function of my map.
This is what I have come up with but I am not able to get a reference to that index value:
if (parseTable.find(std::pair(stack_symbol.top(), current_symbol)))
std::map::find will return an iterator to the found element, or to end if not found. That iterator will point to a std::pair<const Key, Value>, which in your case would translate to
std::pair< const std::pair<Symbol, Symbol>, list<Symbol> >
What you want is something like this
auto it = parseTable.find(std::pair(stack_symbol.top(), current_symbol));
if (it != parseTable.end()) { // A match was found
//it->first is std::pair<Symbol, Symbol>
//it->second is list<Symbol>
for (auto& symbol : it->second) {
//symbol is each individual value in the list
... do something with symbol
}
}
This is not the greatest choice for map key, it won't let the map to be used efficiently.
std::map::find() return an iterator to the place where it found searched item or std::map::end() if not found. So, in your if statement, you need to check against that:
std::map<std::pair<Symbol, Symbol>, list<Symbol> >::iterator iter =
parseTable.find(std::pair(stack_symbol.top(), current_symbol)) //or auto with C++11
if (iter != parseTable.end())
find returns an iterator, to access the object (which will be of type std::pair<std::pair<Symbol, Symbol>, list<Symbol>>, you'll need dereference operator *
Symbol currentSymbol = (*iter).first.second; //dummy example to show the use
std::list<Symbol> myList = (*iter).second'
Suppose you have the incomplete function iterate that has the following parameter, a const map that has pair<int, vector<string>> and the following loops:
string iterate(const map<int, vector<string>>& m) {
for (map<int, vector<string>>::const_iterator start_iter = m.begin(); start_iter != m.end(); ++start_iter) {
for (auto vector_iter = m[(*start_iter).first].begin(); vector_iter != m[(*start_iter).first].end(); ++vector_iter) {
}
}
}
Iterating through a const map requires that the iterator be const, map<int, vector<string>>::const_iterator. That makes sense. However, when trying to iterate through the vector within the constmap what type does auto have to be, or is it not possible to iterate through a container within a const container. I tried making auto vector<string>::const_iterator, but the function still fails. Am I missing something?
Really, do yourself a favor and use range based for loops:
for (auto&& [key, vec] : m) {
for (auto&& vec_element : vec) {
// All vec elements
}
}
If you don't want to use C++17 (you should, C++17 is great!) then do that:
for (auto&& m_element : m) {
for (auto&& vec_element : m_element.second) {
// All vec elements
}
}
If you really want to use use iterators (you really should use range based for loops) then continue reading.
You are not using iterator correctly. You are using a iterator that points on an element in the map, then get it's key to get back the element. This is not how to use an iterator.
Instead, you should use the object the iterator is pointing to directly.
for (auto start_iter = m.begin(); start_iter != m.end(); ++start_iter) {
for (auto vector_iter = start_iter->second.begin(); vector_iter != start_iter->second.end(); ++vector_iter) {
// shuff with vector_iter
}
}
Now why does operator[] failed?
That's because it's a std::map. A with a map, you should be able to create something on the fly:
// creates element at key `123`
m[123] = {"many", "strings", "in", "vector"};
For the element to be created by the container at a new key, it must save that new element in itself, so it must mutate itself to provide operator[], so it's not const.
You could have also use std::map::at(), but it isn't worth it in your case. Using either operator[] or map.at(key) will make the map search for the key, which isn't trivial in complexity.
I have vector of some data type (Let's say-int) and I need to push back only unique values from the file? I am new to use STL. So i don't know how can i do it using map as i read that map only takes unique values. If I simply push back, then it will take all the values irrespective of its uniqueness.
The correct container to use for unique values is either std::set or std::unordered_set:
std::set<int> s;
s.insert(4); // s has size 1
s.insert(5); // s has size 2
s.insert(4); // s still has size 2
If you want to use vector, you'd have to maintain it sorted, which is a lot more code and work, and doesn't have the nice characteristic of set that everybody knows the contents are unique:
void add_value(std::vector<int>& v, int value) {
// do a binary search to find value
std::vector<int>::iterator it = std::lower_bound(v.begin(), v.end(), value);
if (it != v.end() && *it == value) {
// duplicate - do nothing
}
else {
// insert our value here
v.insert(it, value);
}
}
... or I guess you could delete the duplicates at the end using a rarely-used algorithm (std::unique) that will probably raise some eyebrows:
void uniqify(std::vector<int>& v) {
std::sort(v.begin(), v.end());
v.erase(std::unique(v.begin(), v.end()), v.end());
}
[UPDATE] It has been pointed out to me that I completely misunderstood your question - and that you may have been looking for just which values occur exactly once - not a list of which values occur without duplicate. For that, the correct container to use is either a std::map or std::unordered_map - so you can associate a count with a particular key:
std::map<int, int> keyCounts;
int value;
while (fileStream >> value) { // or whatever
++keyCounts[value]; // operator[] gives us a reference to the value
// if it wasn't present before, it'll insert a default
// one - which for int is zero - so this handles
// both cases correctly
}
// Now, any key with value 1 is a unique key
// what you want to do with them is up to you
// e.g., let's put it in a vector
std::vector<int> uniq;
uniq.reserve(keyCounts.size());
for (std::map<int, int>::iterator it = keyCounts.begin(); it != keyCounts.end(); ++it)
{
if (it->second == 1) {
uniq.push_back(it->first);
}
}
A std::map will let you handle a mapping of unique keys to some values (which may or may not be unique). Math-wise, You may see it as a surjective function from the set of keys to the set of values of your dataset.
If your goal is to keep unique indices (or keys), then std::map is what you need. Otherwise, use std::set to store unique values.
Now, to keep only unique values from your dataset, you basically want to remove values which appear more than once. The simplest algorithm is to add values from the file as keys in a map, with its corresponding value being a counter for the number of occurrences of that entry in the file. Initialize a counter to 1 the first time the value is met in the file, and increment it each time it is met again. After having parsed the whole file, simply keep the keys whose values are exactly 1.
Counting the values:
template <typename key>
void count(std::istream &is, std::map<key,int> &map){
while (!is.eof() && is.good()){
key << is;
auto it = map.find(key);
if (it == map.end())
map[key] = 1;
else (*it)++;
}
}
The above assumes that the << has been overloaded to extract values from the stream sequentially. You will have to adapt the algorithm to fit your own way of parsing the data.
Filtering the resulting map to keep unique values can be achieved with std::remove_if and a function returning true when the counter is above 1:
The function:
bool duplicate (std::const_iterator<int> &it){ return *it > 1;}
The map filtering:
std::remove_if (map.begin(), map.end(), duplicate);
assumend I have a (filled) list
std::list<std::pair<int,otherobject>> myList;
and want to find() the first element within this list, where int has a specific value - how can I do that?
To explain it a bit further:
I want to append these pairs to the list with an int that identifies otherobject but is not unique. The order where these int/otherobject pairs arrive has to be kept.
When an int is found during access to elements of this list the first occurence of that int has to be given back (and removed).
Thanks!
I think I'd use the standard find_if algorithm:
auto pos = std::find_if(myList.begin(), myList.end(),
[value](std::pair<int, otherobject> const &b) {
return b.first == value;
});
That gives an iterator to the element with the required value -- from there, you can copy the value, delete the value, etc., just like with any other iterator.
According to your need the better option would be to use a multimap.
In you case it would give :
std::multimap<int, otherobject> myMultiMap;
Then when looking for otherobjects linked to a int ( myInt) you'll do :
std::pair<std::multimap<int, otherobject>::iterator, std::multimap<int, otherobject>::iterator> result = myMultiMap.equal_range(myInt);
for (std::multimap<int,otherobject>::iterator iter=result.first; iter!=result.second; ++iter)
{
std::cout << it->second;
}
This is a STL container so you'll easilly find online documentation.
I dont understand what does that piece of code does
static TwoWayHostPair hostpair;
map <TwoWayHostPair, Traffic> mymap;
//here some map element inserted to mymap and hostpair initialized
map <TwoWayHostPair, Traffic>::iterator iter = mymap.begin();
iter = mymap.find(hostpair);
if (iter == mymap.end()) {
iter = mymap.insert(make_pair(hostPair, Traffic())).first; //line8
}
My question is what happens in line8? I didnt get it. Isnt it supposed to be type map<...>:iterator and after this insertion does it stay same type?
std::map::insert return std::pair< iterator,bool >, below statement is correct. second bool return value indicates whether the insertion took place
iter = mymap.insert(make_pair(hostPair, Traffic())).first; //line8
see reference here
As used here,
iter = mymap.insert(make_pair(hostPair, Traffic())).first; //line8
mymap.insert returns a pair<iterator,bool>. first, then, accesses the iterator.
insert(make_pair......
make_pair is used to insert pair value to a map.You have iterated for all the element in map having hostpair.
EDIT
Refer cplusplus map to know more.
iter = mymap.find(hostpair);
if (iter == mymap.end()) {
iter = mymap.insert(make_pair(hostPair, Traffic())).first; //line8
}
The first line looks for key hostPair in the map, and if it is not found, then it enters the if block where it inserts the key along with its value, and .first returns the iterator to the inserted item.
Improvement
But you can make an improvement to this. You could just write this:
iter = mymap.insert(make_pair(hostPair, Traffic())).first;
which is exactly equivalent to your code. No need to use find and then insert. The result is a performance gain.
If the key already exists, the insert function will NOT insert any item to the map and .first will return you the iterator to the found item. If the key doesn't exist, only then it will insert and .first will return you the iterator to the newly inserted item.
If you want to know whether the key already existed or not, then you can do this:
auto pair = mymap.insert(make_pair(hostPair, Traffic())); //NO .first!
if (pair.second)
{
//a newly created item is inserted
auto iter = pair.first; //iterator to the newly inserted item
}
else
{
//an item with key `hostPair` already exists in the map
auto iter = pair.first; //iterator to the found item
}
Hope that helps.