the value of iterator - c++

i created a map.
i want to print the index of the key to a file using the itr in the map.
this is what i mean:
map <string,int> VendorList;
VendorList[abc] = 0;
VendorList[mazda] = 111;
VendorList[ford] = 222;
VendorList[zoo] = 444;
map <string,int>::iterator itr=VendorList.find("ford");
fstream textfile;
textfile << itr;
if i put in the find line abc i wish the program to cout 1.
if i put in the find line mazda i wish the program to cout 2.
if i put in the find line ford i wish the program to cout 3.
if i put in the find line zoo i wish the program to cout 4.
how do i do that?
the compiler is shouting on the line:
textfile << itr;
it gives this error:
error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'std::_Tree<_Traits>::iterator' (or there is no acceptable conversion)

Your program has many bugs. Frankly speaking I am not sure about your requirement.
But anyways try this :
map <string,int> VendorList;
VendorList["abc"] = 1;
VendorList["mazda"] = 2;
VendorList["ford"] = 3;
VendorList["zoo"] = 4;
map <string,int>::iterator itr=VendorList.find("ford");
cout<<(itr->second);// this will print 3
EDIT :
Also as somebody has suggested to use vector of pairs,I think he is right. Try something like this.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
typedef vector<pair<string,int> > Vm;
Vm V;
V.push_back(make_pair("abc",0));
V.push_back(make_pair("mazda",111));
V.push_back(make_pair("ford",222));
V.push_back(make_pair("zoo",444));
for(size_t i=0;i!=V.size();++i)
if(V[i].first=="ford")
cout<<(i+1);
}
Modify the above program as per requirement.
Hope that helps.

In map, the elements aren't stored in the order of insertion, so you have to hold the "order" data yourself.
I would suggest you to consider using a vector of pairs instead of a map. Vector does store the elements in the order of insertion, and its iterator is Random-Access so you will be able to check the position using the operator-.
vector <pair<string, int> >::iterator itr;
// itr = the needed element
cout << itr - VendorList.begin();

As such, the concept of 'index' doesn't really fit with Maps.
Maps are just key-value pairs where you store a value (say, '111') and access it using a key (say 'mazda'). In this way you don't really need an index in order to access '111', you can just use the key 'mazda'.
If you do want your application to be index based however, consider using a different data structure like a Vector or a Linked List.

Related

Vector of set insert elements

I'm trying to write a function which will return vector of set type string which represent members of teams.
A group of names should be classified into teams for a game. Teams should be the same size, but this is not always possible unless n is exactly divisible by k. Therefore, they decided that the first mode (n, k) teams have n / k + 1 members, and the remaining teams have n / k members.
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <list>
typedef std::vector<std::set<std::string>>vek;
vek Distribution(std::vector<std::string>names, int k) {
int n = names.size();
vek teams(k);
int number_of_first = n % k;
int number_of_members_first = n / k + 1;
int number_of_members_remaining = n / k;
int l = 0;
int j = 0;
for (int i = 1; i <= k; i++) {
if (i <= number_of_first) {
int number_of_members_in_team = 0;
while (number_of_members_in_team < number_of_members_first) {
teams[l].insert(names[j]);
number_of_members_in_team++;
j++;
}
}
else {
int number_of_members_in_team = 0;
while (number_of_members_in_team < number_of_members_remaining) {
teams[l].insert(names[j]);
number_of_members_in_team++;
j++;
}
}
l++;
}
return teams;
}
int main ()
{
for (auto i : Distribution({"Damir", "Ana", "Muhamed", "Marko", "Ivan",
"Mirsad", "Nikolina", "Alen", "Jasmina", "Merima"
}, 3)) {
for (auto j : i)
std::cout << j << " ";
std::cout << std::endl;
}
return 0;
}
OUTPUT should be:
Damir Ana Muhamed Marko
Ivan Mirsad Nikolina
Alen Jasmina Merima
MY OUTPUT:
Ana Damir Marko Muhamed
Ivan Mirsad Nikolina
Alen Jasmina Merima
Could you explain me why names are not printed in the right order?
teams being a std::vector<...> supports random access via an index.
auto & team_i = teams[i]; (0 <= i < teams.size()), will give you an element of the vector. team_i is a reference to type std::set<std::list<std::string>>.
As a std::set<...> does not support random access via an index, you will need to access the elements via iterators (begin(), end() etc.), e.g.: auto set_it = team_i.begin();. *set_it will be of type std::list<std::string>.
Since std::list<...> also does not support random access via an index, again you will need to access it via iterators, e.g.: auto list_it = set_it->begin();. *list_it will be of type std::string.
This way it is possible to access every set in the vector, every list in each set, and every string in each list (after you have added them to the data structure).
However - using iterators with std::set and std::list is not as convenient as using indexed random access with std::vector. std::vector has additional benefits (simple and efficient implementation, continous memory block).
If you use std::vectors instead of std::set and std::list, vek will be defined as:
typedef std::vector<std::vector<std::vector<std::string>>> vek;
std::list being a linked list offers some benefits (like being able to add an element in O(1)). std::set guarentees that each value is present once.
But if you don't really need these features, you could make you code simpler (and often more efficient) if you use only std::vectors as your containers.
Note: if every set will ever contain only 1 list (of strings) you can consider to get rid of 1 level of the hirarchy, I.e. store the lists (or vectors as I suggested) directly as elements of the top-level vector.
UPDATE:
Since the question was changed, here's a short update:
In my answer above, ignore all the mentions of the std::list. So when you iterate on the set::set the elements are already std::strings.
The reason the names are not in the order you expect:
std::set keeps the elements sorted, and when you iterate it you will get the elements by that sorting order. See the answer here: Is the std::set iteration order always ascending according to the C++ specification?. Your set contains std::strings and the default sort order for them is alphabetically.
Using std::vector instead of std::set like I proposed above, will get you the result you wanted (std::vector is not sorted automatically).
If you want to try using only std::vector:
Change vek to:
typedef std::vector<std::vector<std::string>>vek;
And replace the usage of insert (to add an element to the set) with push_back to do the same for a vector.

How would I print out a map in descending order?

So I'm trying to iterate through the map from greatest to least and it has to print the top 10. I have to use map.h because its required so I can't use the normal map, I also cant use a vector. How would I just get the top 10 from the map from descending order?
Here is the link to the Stanford Map Library
#include <iostream>
#include "map.h"
using namespace std;
Map <string, int> wordFreq;
int counter = 0;
int max = 0;
for(string s : wordFreq)
{
if(wordFreq[s] > max)
{
counter++;
max = wordFreq[s];
cout << s << " : " << max << endl;
}
if(counter == 10)
{
exit(0);
}
}
I've been at this for a couple of hours so I think my logic is just bad.
If you only need top 10 value, you should use a minHeap with a size of 10 as you don't need to sort all the elements in the map.
Then sort the elements in minHeap before return if you need(maybe unsorted top10 values are excepted).
This class has no way to iterate it other than a "visit all" function. So there's not going to be any good way to do it.
A simple hack is as follows:
Flip the sign of every int you use as a key before storing it in the map.
This will cause the map to visit its elements in reverse order.
Call mapAll with a visitor function that only prints the first ten times it's called. Don't forget to flip the sign of each key before printing it.
A less hacky way is to create reversedInt class that acts like an int but compares in reverse. That will avoid the need to flip signs and still let the map traverse in reverse.
It seems the provided Map class can accept a comparator in its constructor. So this might be the intended way to do this, I guess.
But the provided Map class is really just not suitable for this use.

Is there any way to store element and its frequency together in same data structure?

I have been working on a problem with arrays and the count of each elements must be considered and changed dynamically then and there. I want to know if there is a way to store both the element and frequency in a single data structure.
Any solution with code in cpp would be helpful.
int main()
{
int a[]={1,1,1,2,2,3,4};
map<int,int> m;
map<int,int>::iterator it;
for(int i=0;i<7;i++)
{
it=m.find(a[i]);
if(it!=m.end()) it->second++;
else m.insert(pair<int,int>(a[i],1));
}
//printing the output
for(auto i=m.begin();i!=m.end();i++)
cout<<i->first<<"->"<<i->second<<"\n";
}
yeah, you use maps to store the element with its count. Here I have used an iterator along with find function in order to check if the element is present.
if present increase the count by 1 i.e it->second++. else you can insert the new element in the map using insert function.

C++ Map returning class object based on variable key

I reacently learned about map structures and I am trying to use one, but can't seem to solve one problem.
I have tried the code below:
map<string, valuePair> translator;
The class valuePair is just a combination of 2 objects (string and a number).
Im assigning values to the map
translator[currentWord] = valuePair(stateNo, "state");
Where currentWord is a variable string, stateNo is an int.
Now later I want to get back the valuePair number value from the map, but can;t seem to be able to do it.
Heres a screenshot of my watch window trying to access the variable x.
http://i.imgur.com/m3MOgi2.png
These are all the ways I managed to find online to return the value, yet none of them seem to work. As you can see the key "a" is in the map. What am I doing wrong?
[EDIT] Thanks guys, I used the tips you gave in comments and found out, that actually it works the way I expected - translator["a"].x prints the values I need. I have nothing to mark as "Correct answer" though, and I'm not sure what to do with this thread now :/
As Jonathan Henson posted in the comments, you would be better off posting your code than your debugger output. Ideally you want a minimal example that reproduces the error you are having.
Based on the debugger output, I'm wondering if you have a scope issue -- you are trying to access the map data outside of the scope where you have it defined. Without seeing the source code though, there is no way to know.
Here is a working example that does precisely what you are trying to do. The only modification is I have used a struct for valuePair, and c++ 11 initializer lists. This won't affect the map access code, but you might need to turn on c++ 11 support to compile it.
As a first step, look check it out in your debugger and see if you get the same difficulty. If so, your problem is the debugger or debugger setup, not your code.
If the debugger works for the sample code (posted below), gradually transform my code into your code (making minimal changes, building, and see if it still works). This is a very useful approach to learning the fine points of a language.
#include <iostream>
#include <map>
#include <string>
using namespace std;
struct valuePair
{
int num;
string str;
};
int main()
{
map<string, valuePair> translator;
translator["a"] = {0,"bla"};
translator["b"] = {1, "alb"};
translator["c"] = {2, "lab"};
valuePair res = translator["c"];
cout << "c:" << res.num << "," << res.str << "\n";
res = translator.at("b");
cout << "b:" << res.num << "," << res.str << "\n";
res = translator.find("a")->second;
cout << "a:" << res.num << "," << res.str << "\n";
return 0;
}
If you have an std::map<K,V> m; you can add elements and change values by using m[k] = v;. However the operator[] is an operation which always creates a key/value pair, if the key you are looking for is not contained in the map. Thus it is not allowed when you have a const reference or pointer, e.g. const std::map<K,V>&.
With a std::map you always have to consider the case that the key you are looking for is actually not contained in the map!
To look for the value stored under a given key you have to use std::map::find (link).
Example:
std::map<std::string,valuePair>::const_iterator it = translator.find(currentWord);
if(it != translator.end()) {
// the map contains an element with this key
const valuePair& value = it->second; // this is the value
}
else {
// the map *does not* contain an element with this key
}
As mentioned in the comments std::map::at (link) may be an alternative for C++11. But then you have to take care of the possible exception which is thrown when you use a key which does not exist in the map.
this works for me
#include <map>
#include <sstream>
#include <string>
int main()
{
std::map<std::wstring, double> items;
items[L"0"] = 0.123;
items[L"1"] = 1.234;
items[L"2"] = 2.234;
items[L"3"] = 3.345;
items[L"4"] = 4.567;
for (int i = 0; i < 5; i++)
{
std::wstringstream oss;
oss << i;
std::wstring key = oss.str();
double value = items[key];
}
return 0;
}

Random element in a map

what is a good way to select a random element from a map? C++. It is my understanding that maps don't have random access iterators. The key is a long long and the map is sparsely populated.
map<...> MyMap;
iterator item = MyMap.begin();
std::advance( item, random_0_to_n(MyMap.size()) );
I like James' answer if the map is small or if you don't need a random value very often. If it is large and you do this often enough to make speed important you might be able to keep a separate vector of key values to select a random value from.
map<...> MyMap;
vector<...> MyVecOfKeys; // <-- add keys to this when added to the map.
map<...>::key_type key = MyVecOfKeys[ random_0_to_n(MyVecOfKeys.size()) ];
map<...>::data_type value = MyMap[ key ];
Of course if the map is really huge you might not be able to store a copy of all the keys like this. If you can afford it though you get the advantage of lookups in logarithmic time.
Maybe draw up a random key, then use lower_bound to find the closest key actually contained.
Continuing ryan_s theme of preconstructed maps and fast random lookup: instead of vector we can use a parallel map of iterators, which should speed up random lookup a bit.
map<K, V> const original;
...
// construct index-keyed lookup map
map<unsigned, map<K, V>::const_iterator> fast_random_lookup;
map<K, V>::const_iterator it = original.begin(), itEnd = original.end();
for (unsigned i = 0; it != itEnd; ++it, ++i) {
fast_random_lookup[i] = it;
}
// lookup random value
V v = *fast_random_lookup[random_0_to_n(original.size())];
If your map is static, then instead of a map, use a vector to store your key/value pairs in key order, binary search to look up values in log(n) time, and the vector index to get random pairs in constant time. You can wrap the vector/binary search to look like a map with a random access feature.
Maybe you should consider Boost.MultiIndex, although note that it's a little too heavy-weighted.
Here is the case when all map items must be access in random order.
Copy the map to a vector.
Shuffle vector.
In pseudo-code (It closely reflects the following C++ implementation):
import random
import time
# populate map by some stuff for testing
m = dict((i*i, i) for i in range(3))
# copy map to vector
v = m.items()
# seed PRNG
# NOTE: this part is present only to reflect C++
r = random.Random(time.clock())
# shuffle vector
random.shuffle(v, r.random)
# print randomized map elements
for e in v:
print "%s:%s" % e,
print
In C++:
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/foreach.hpp>
#include <boost/random.hpp>
int main()
{
using namespace std;
using namespace boost;
using namespace boost::posix_time;
// populate map by some stuff for testing
typedef map<long long, int> Map;
Map m;
for (int i = 0; i < 3; ++i)
m[i * i] = i;
// copy map to vector
#ifndef OPERATE_ON_KEY
typedef vector<pair<Map::key_type, Map::mapped_type> > Vector;
Vector v(m.begin(), m.end());
#else
typedef vector<Map::key_type> Vector;
Vector v;
v.reserve(m.size());
BOOST_FOREACH( Map::value_type p, m )
v.push_back(p.first);
#endif // OPERATE_ON_KEY
// make PRNG
ptime now(microsec_clock::local_time());
ptime midnight(now.date());
time_duration td = now - midnight;
mt19937 gen(td.ticks()); // seed the generator with raw number of ticks
random_number_generator<mt19937,
Vector::iterator::difference_type> rng(gen);
// shuffle vector
// rng(n) must return a uniformly distributed integer in the range [0, n)
random_shuffle(v.begin(), v.end(), rng);
// print randomized map elements
BOOST_FOREACH( Vector::value_type e, v )
#ifndef OPERATE_ON_KEY
cout << e.first << ":" << e.second << " ";
#else
cout << e << " ";
#endif // OPERATE_ON_KEY
cout << endl;
}
Has anyone tried this?
https://github.com/mabdelazim/Random-Access-Map
"C++ template class for random access map. This is like the std::map but you can access items random by index with syntax my_map.key(i) and my_map.data(i)"
std::random_device dev;
std::mt19937_64 rng(dev());
std::uniform_int_distribution<size_t> idDist(0, elements.size() - 1);
auto elementId= elements.begin();
std::advance(elementId, idDist(rng));
Now elementId is random :)