Is it possible to print map in c++ without using iterator ?
something like
map <int, int>m;
m[0]=1;
m[1]=2;
for(int i =0; i<m.size(); i++)
std::cout << m[i];
Is it necessary to make iterator for printing map value ?
If you simply want to avoid typing out the iterator boilerplate, you can use a range-for loop to print each item:
#include <iostream>
#include <map>
int main() {
std::map<int,std::string> m = {{1, "one"}, {2, "two"}, {3, "three"}};
for (const auto& x : m) {
std::cout << x.first << ": " << x.second << "\n";
}
return 0;
}
Live example: http://coliru.stacked-crooked.com/a/b5f7eac88d67dafe
Ranged-for: http://en.cppreference.com/w/cpp/language/range-for
Obviously, this uses the map's iterators under the hood...
Is it necessary to make iterator for printing map value ?
Yes you need them, you can't know what keys been inserted in advance. And your code is not correct, think about
map <int, int>m;
m[2]=1;
m[3]=2;
for(int i =0; i<m.size(); i++)
std::cout << m[i]; // oops, there's not m[0] and m[1] at all.
// btw, std::map::operator[] will insert them in this case.
Related
I was studying the library in C++ and I can't understand why my code isn't working... Can you help me please?
void Vect_Visualizza (vector<int> vect) {
for (auto it = vect.begin(); it != vect.end(); ++it)
cout << vect.at(it) << " ";
}
Very slight change.
void Vect_Visualizza (vector<int> vect) {
for (auto it = vect.begin(); it != vect.end(); ++it)
cout << *it << " ";
}
Think of the iterator as a pointer, not an index. begin() and end() return iterators. You'll want to read about them. They're confusing at first.
You can also do this:
for (int &i: vect) {
cout << i << endl;
}
Which is a lot easier unless you really, really need the iterator itself.
V.at(i) is same as V[i]
so it fails in your case because you are trying to use at() with iterator,which is wrong.
at() function expects an integer input, which is the index of the element we intend to access.
consider the code below:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int>v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
cout<<"indexed output: "<<v[1]<<"\n";
cout<<"output using at: "<<v.at(2)<<"\n";
}
output is:
indexed output: 2
output using at: 3
from this we can observe that using at() is same as indexed access.
Iterator works similar to pointer,hence you can write
cout<<*it
So I've started learning vectors for the first time and wrote a simple program which goes like this:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> g1;
int n;
cout<<"enter values"<<endl;
do
{
cin>>n;
g1.push_back(n);
} while (n);
cout<<"Vector values are: "<<endl;
for(auto i=g1.begin(); i<g1.size();i++)
cout<<*i<<endl;
}
When I try executing it, an error shows up saying "type mismatch" at the g1.size() part. Why exactly does this happen? I used the auto keyword for the iterator involved and assumed there wouldn't be any problem?
That is the bad side of using auto. If you have no idea what the result of auto is, you get no idea why it is something totally different you expect!
std::vector::begin delivers a std::vector::iterator and you can't compare it against an size_type value which is a result of std::vector::size. This type is typically std::size_t
You have to compare against another iterator which is the representation of the end of the vector like:
for(auto i = g1.begin(); i != g1.end(); i++)
There are at least three ways to iterate through the contents of a vector.
You can use an index:
for (int i = 0; i < vec.size(); ++i)
std::cout << vec[i] << '\n';
You can use iterators:
for (auto it = vec.begin(); it != vec.end(); ++it)
std::cout << *it << '\n';
You can use a range-based for loop:
for (auto val : vec)
std::cout << Val <<'\n';
The latter two can be used with any container.
g1.begin() returns an iterator to the 1st element, whereas g1.size() returns the number of elements. You can't compare an iterator to a size, which is why you are getting the error. It has nothing to do with your use of auto, it has to do with you comparing 2 different things that are unrelated to each other.
You need to change your loop to compare your i iterator to the vector's end() iterator, eg:
for(auto i = g1.begin(); i != g1.end(); ++i)
cout << *i << endl;
Or, simply use a range-based for loop instead, which uses iterators internally:
for(auto i : g1)
cout << i << endl;
Otherwise, if you want to use size() then use indexes with the vector's operator[], instead of using iterators, eg:
for(size_t i = 0; i < g1.size(); ++i)
cout << g1[i] << endl;
I am trying to use a class to make a dictionary < key, value > in C++.
I found online that Map was the class I was suppoused to use.
However, when I try to use Map it FILLS the gaps between the keys.
This is an issue because keys are numbers, but they are incredibly sparse.
So in one set I may have the keys [1 , 20, 30000, 70000000]. I want my map to just store those 4 values, not every values between 1 and 70000000.
#include <iostream>
#include <map>
using namespace std;
int main()
{
map<int,int> a = {{1,-1},{20,200}}; // I want this to just store {1,20}
for(int x = 0; x < a.size(); x++) cout << a[p(x)] << ","; //however, when I print it I get [0,1..,19,20]
return 0;
}
OUTPUT
0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,200,
Is there some workaround to avoid C++ from "filling the gaps" or any other class in the STD that can be used for that purpose?
map::operator[] create entry for you (and increase it's size()). If you just want to iterate through std::map, use it's iterator.
for(auto& entry : a) cout << entry.second << ",";
As apple has commented, the operator[] creates the entry. See:
http://www.cplusplus.com/reference/map/map/operator[]/
mapped_type& operator[] (const key_type& k);
If k does not match the key of any element in the container, the function inserts a new element with that key and returns a reference to its mapped value.
If you want to check existence of the key, use map::find().
Here are some ways to print out the map: you can use a for-each loop or an iterator:
#include <iostream>
#include <map>
#include <random>
using namespace std;
int main()
{
map<int, int> myMap;
// filling map with random elements
random_device rd;
mt19937 rng(rd());
uniform_int_distribution<int> uni(0,1000);
for(int i = 0; i < 10; i++) {
// uses the [] operator to create an element
myMap[uni(rng)] = uni(rng);
}
// first method to print out map using for-each loop
for(auto a : myMap) {
// cannot change elements in map
cout << a.first << " " << a.second << endl;
}
// second method to print out map using iterator
for(map<int, int>::iterator it = myMap.begin(); it != myMap.end(); it++) {
// can change elements in map
cout << it->first << " " << it->second << endl;
}
}
Hope this helps!
By the way, thinking of using map is actually very intelligent when creating a dictionary, because map elements are automatically sorted! I assume you are mapping strings to ints, right?
How to iterate through the contents of map["a"] to retrieve call and call1 ?
std::vector<std::string> point
std::map<std::string, point> alloc
map["a"] = call, call1
map["i"] = call
I have tried using for loop using map iterator and inside that for loop another for loop on the vector and then checking whether the value of map iterator map equals "a" but keep getting an error.
I think you are misunderstanding some syntax and of the programming language and the semantics of the standard library containers a little bit. I will explain what I think you are doing wrong.
First thing is that you have a vector of string objects called point, this is an object not a type. An object is a variable of a type, for example
string name = "curious";
Here name is an object of type/class string, so you cannot type in point as the template parameter to the map, you have to type in a type. So that should be a string.
Second thing is that you are using the comma operator, I am not sure if you knew that you were doing that. The comma operator works as follows
#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;
int main() {
cout << ("Hello", "World") << endl;
return 0;
}
^ this will generate a compiler error because the "Hello" is not used but the point is that the comma operator evaluates the first part of the expression and then returns the thing on the right; so this will print
World
Third thing is how you iterate through the map. When you iterate through a std::map in C++ you are actually iterating through a series of std::pairs so the following code
#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;
#include <map>
using std::map;
int main() {
map<string, int> map_string_int {{"curious", 1}, {"op", 2}};
for (auto iter = map_string_int.begin(); iter != map_string_int.end();
++iter) {
cout << iter->first << " : " << iter->second << endl;
}
return 0;
}
will produce the following output
curious : 1
op : 2
the keys will be ordered alphabetically because they are stored in a binary search tree (https://en.wikipedia.org/wiki/Binary_search_tree)
Now I think you wanted to have a map from string objects to vectors, so you would structure your code as such
std::vector<string> point
std::map<string, std::vector<string>> alloc;
alloc["a"] = {"call", "call1"};
alloc["i"] = {"call"};
and you would iterate through this like so
for (auto iter = alloc.begin(); iter != alloc.end(); ++iter) {
cout << iter->first << " : " << iter->second << endl;
}
You would iterate through alloc["a"] like so
// sanity check
assert(alloc.find("a") != alloc.end());
for (auto iter = alloc["a"].begin(); iter != alloc["a"].end(); ++iter) {
cout << *iter << endl;
}
Hope that helped!
I assume you mean std::multimap instead of std::map, based on your use case (multiple values under the same key). It's in the same <map> header.
std::multimap<std::string, int> map;
map.insert(std::make_pair("first", 123));
map.insert(std::make_pair("first", 456));
auto result = map.equal_range("first");
for (auto it = result.first; it != result.second; ++it)
std::cout << " " << it->second;
Reference: std::multimap::equal_range
This should do what you want if I understand correctly.
std::vector<string> point = { "Hello", "World" };
std::map<std::string, decltype(point)> my_map;
//if you dont wan't to use decltype (or cant):
//std::map<std::string, std::vector<std::string>> my_map;
my_map["A"] = point;
my_map["B"] = { "Something", "Else" };
//this will iterate only trought my_map["A"]
for (const auto &vector_val : my_map["A"])
std::cout << vector_val << std::endl;
//this will iterate trought the whole map
for (const auto &map_pair : my_map)
{
std::cout << "map: " << map_pair.first << std::endl;
for (const auto &vector_val : map_pair.second)
std::cout << vector_val << std::endl;
std::cout << "---------------------------------" << std::endl;
}
I'm curious about knowing what is more suitable in such situations i.e multimap or map_of_vectors .
If sequencially someone want to iterate vector associated to a particular/all keys in map
what will be more efficient/optimal.
map<string ,vector<string>> mp;
// initialize your map...
for(auto itr=mp.begin(); itr!=mp.end() ;itr++)
for(auto itr2=itr->second.begin(); itr2!=itr->second.end() ;itr2++)
cout<<*itr2
for particular key just change first loop as stated down
auto itr=mp.find(key);
I am looping through std::vector and std::string array to find matches from the vector.
Example:
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::cout << "Searching...\n";
std::vector<std::string> myVector;
myVector.push_back("Word");
myVector.push_back("Word2");
myVector.push_back("Word4");
myVector.push_back("Word6");
myVector.push_back("Word7");
std::string myStringArr[] =
{
"Word",
"Word1",
"Word2",
"Word3",
"Word4",
"Word5",
"Word6",
"Word7"
};
for (auto Vec : myVector)
{
for(auto Str : myStringArr)
{
if(Vec == Str)
{
std::cout << "Found: " << Vec << std::endl;
}
}
}
std::cin.ignore(2);
return 0;
}
This works fine. But I am coming from C language(trying to get into C++ 11), and not sure if this is the best solution.
Platform is windows, and I do not (currently) use any external libraries like boost, as you can see from the code.
Is there a better / cleaner way to achieve the same result?
Your solution works fine and is good as long as the vector and the string array are not too long.
Little improvement on the code: don't use auto for simple types, it's just less readable (you could use const string& instead).
You could do something more efficient: Your algorithm complexity is O(NxM) with N and M the sizes of the vector and array.
Storing the values of the vector in a hash_set and then checking if they are in the array would be O(N+M).
If your array and vector are sorted, you can use std::set_intersection.
According to cplusplus.com, the complexity is Up to linear in 2*(count1+count2)-1 (where countX is the distance between firstX and lastX): Compares and assigns elements.
If they are not, you can sort them first, which only take O(nlog(n) + mlog(m)) (with n being the number of elements in the vector, and m in the array (or vice versa)) time, before linear for the range (this is better than your O(n*m) solution).
Here how it looks like :
#include <iostream> // std::cout
#include <algorithm> // std::set_intersection, std::sort
#include <vector> // std::vector
std::vector<std::string> intersection(myVector.size()); //needs to be allocated
std::sort (myVector.begin(),myVector.end());
std::sort (myStringArr,myStringArr+10);
auto it = std::set_intersection (myVector.begin(), myVector.end(), //first range
myStringArr, myStringArr+10, // second range
intersection.begin()); // the result range
v.resize(it-v.begin());
std::cout << "The intersection has " << (v.size()) << " elements:\n";
Yes, you can use std::find_first_of for this:
auto itVec = myVector.begin();
for (;;) {
itVec = std::find_first_of(itVec, myVector.end(), std::begin(myStringArr), std::end(myStringArr);
if (itVec == myVector.end())
break;
std::cout << "Found: " << *itVec << '\n';
++itVec;
}
Use std::find_first_of:
for (auto str : myStringArr)
{
if (std::find_first_of(str, std::begin(myVector). std::end(myVector))
{
std::cout << "Found: " << str << std::endl;
}
}
You can use std::set to store your strings:
std::set<std::string> myStringSet
{
"Word",
"Word1",
"Word2",
"Word3",
"Word4",
"Word5",
"Word6",
"Word7"
};
for (auto Vec : myVector)
{
if( myStringSet.count( Vec ) )
{
std::cout << "Found: " << Vec << std::endl;
}
}
}
Another solution is to sort your vector and use std::binary_search:
std::vector<std::string> myStringArr
{
"Word",
"Word1",
"Word2",
"Word3",
"Word4",
"Word5",
"Word6",
"Word7"
};
std::sort( myStringArr.begin(), myStringArr.end() );
for (auto Vec : myVector)
{
if( std::binary_search( myStringArr.begin(), myStringArr.end(), Vec ) {
std::cout << "Found: " << Vec << std::endl;
}
}
The std::set_intersection algorithm does what you want.
Sort your two data structures using std::sort (or use sorted data structures instead) :
std::sort(myVector.begin(), myVector.end());
std::sort(myStringArr, myStringArr + 8);
And then use std::set_intersection :
std::set_intersection(
myVector.begin(), myVector.end(),
myStringArr, myStringArr + 8,
std::ostream_iterator<std::string>(std::cout, "\n"));
Note the use of std::ostream_iterator for printing the result on std::cout.
Since, in general case, both vector and array are not sorted, you have to iterate over every element. Therefore that is the best way.
Only one small thing. for (auto Vec : myVector) is going to make a copy of each element. Since std::string makes shallow copy, you will not notice. But in some other case, it may be noticable. Better way would be to use a reference :
for (const auto& Vec : myVector)