I would like to loop through two maps at the same time, how could I achieve this?
I have two vectors want to print both, can I do two time (auto it : mymap) within one for? Something like:
for (auto it: mymap && auto on: secondMap)
is this even allowed?
I am trying to print values like (value1, value2) where each of the values is in a different map. The maps do not necessarily contain the exact same items but the key is an Instruction and the value is an integer, so if I have a element in the map for value2, then not necessarily there is a value1 corresponding to the same key, but in that case it should be 0 which is the default integer value.
Any ideas?
Perhaps it is possible to combine two iterators, one for each map?
Kind regards,
Guus Leijsten
You can use the regular for-loop for this :
#include <iostream>
#include <map>
int main(int argc, char* argv[]) {
std::map<int, std::string> m1, m2;
m1.insert({15, "lala"});
m1.insert({10, "hey!"});
m1.insert({99, "this"});
m2.insert({50, "foo"});
m2.insert({51, "bar"});
for(auto it_m1 = m1.cbegin(), end_m1 = m1.cend(),
it_m2 = m2.cbegin(), end_m2 = m2.cend();
it_m1 != end_m1 || it_m2 != end_m2;)
{
if(it_m1 != end_m1) {
std::cout << "m1: " << it_m1->first << " " << it_m1->second << " | ";
++it_m1;
}
if(it_m2 != end_m2) {
std::cout << "m2: " << it_m2->first << " " << it_m2->second << std::endl;
++it_m2;
}
}
return EXIT_SUCCESS;
}
Note that because you want to iterate over maps of different size, you have to use the || operator in loop condition. The direct consequence is that you cannot increment in the last part of the for-loop, as one of the iterator may be invalid at that time (and lead to a segmentation fault).
You have to check iterator validity inside the loop and increment it when it's valid, as shown in the sample above.
Related
I am creating a scrabble game and i need to have a basic score to words on the dictionary.
I used make_tuple and stored it inside my tuple. Is there a way to access elements in a tuple as if it was in a vector?
#include <iostream>
#include <tuple>
#include <string>
#include <fstream>
void parseTextFile()
{
std::ifstream words_file("scrabble_words.txt"); //File containing the words in the dictionary (english) with words that do not exist
std::ofstream new_words_file("test.txt"); //File where only existing words will be saved
std::string word_input;
std::tuple<std::string, int> tupleList;
unsigned int check_integrity;
int counter = 0;
while(words_file >> word_input)
{
check_integrity = 0;
for (unsigned int i = 0; i < word_input.length(); i++)
{
if((int)word_input[i] >= 97 && (int)word_input[i] <= 123) //if the letter of the word belongs to the alphabet
{
check_integrity++;
}
}
if(word_input.length() == check_integrity)
{
new_words_file << word_input << std::endl; //add the word to the new file
tupleList = std::make_tuple(word_input, getScore(word_input)); //make tuple with the basic score and the word
counter++; //to check if the amount of words in the new file are correct
std::cout << std::get<0>(tupleList) << ": " << std::get<1>(tupleList) << std::endl;
}
}
std::cout << counter << std::endl;
}
One would generally use a tuple when there are more than two values of different types to store. For just two values a pair is a better choice.
In your case what you want to achieve seems to be a list of word-value pairs. You can store them in a container like a vector but you can also store them as key-value pairs in a map. As you can see when following the link, an std::map is literally a collection of std::pair object and tuples are a generalization of pairs.
For completeness, if my understanding of your code purpose is correct, these are additions to your code for storing each tuple in a vector - declarations,
std::tuple<std::string, int> correct_word = {};
std::vector<std::tuple<std::string, int>> existing_words = {};
changes in the loop that saves existing words - here you want to add each word-value tuple to the vector,
if(word_input.length() == check_integrity)
{
// ...
correct_word = std::make_tuple(word_input, getScore(word_input));
existing_words.push_back(correct_word);
// ...
}
..and finally example of usage outside the construction loop:
for (size_t iv=0; iv<existing_words.size(); ++iv)
{
correct_word = existing_words[iv];
std::cout << std::get<0>(correct_word) << ": " << std::get<1>(correct_word) << std::endl;
}
std::cout << counter << std::endl;
The same code with a map would look like:
The only declaration would be a map from strings to values (instead of a tuple and vector of tuples),
std::map<std::string, int> existing_words = {};
In the construction loop you would be creating the map pair in a single line like this,
if(word_input.length() == check_integrity)
{
// ...
existing_words[word_input] = getScore(word_input);
// ...
}
While after constructing you would be accessing map elements using .first for the word and .second for the counter. Below is a printing example that also uses a for auto loop:
for (const auto& correct_word : existing_words)
std::cout << correct_word.first << ": " << correct_word.second << std::endl;
std::cout << counter << std::endl;
Notice that maps are by default alphabetically ordered, you can provide your own ordering rules and also use an unordered map if you don't want any ordering/sorting.
I have a map as below :
std::map< std::string ,int> mapobj;
mapobj["one"] = 1;
mapobj["two"] = 2;
mapobj["three"] =3 ;
how to get key when input is value
EX :
input : 1
output : one
Note : In my case value is unique
A one-to-one mapping is actually quite easy, the fastest way to do it is to probably maintain two maps, one for each direction. It becomes more complicated if it's not one-to-one since you'll need to provide a way to get a collection of values or key, rather than a single one. Happily, you only have the one-to-one requirement.
One of the maps is the one you have now, the other will map the values to a given key, soboth would be:
std::map<std::string, int> forwardmapobj;
std::map<int, std::string> reversemapobj;
and these would be maintained within a bidimap class of some sort.
Whenever you insert to, or delete from, your bidimap, you have to perform the equivalent operation on both internal maps.
For example, here's some pseudo-code. It maintains the two maps and ensures that they'e kept in sync for whatever operations you have that change the keys and values:
class biDiMap:
map<string, int> forwardMap
map<int, string> reverseMap
void add(string key, int val):
if exists forwardMap[key]: throw exception 'duplicate key'
if exists reverseMap[val]: throw exception 'duplicate value'
forwardMapObj[key] = val
reverseMapObj[val] = key
void delKey(string key):
if not exists forwardMap[key]: throw exception 'no such key'
delete reverseMap[forwardMap[key]]
delete forwardMap[key]
void delVal(int val):
if not exists reverseMap[val]: throw exception 'no such value'
delete forwardMap[reverseMap[val]]
delete reverseMap[val]
int getValFor(string key): return forwardMap[key]
string getKeyFor(int val): return reverseMap[val]
Obviously, there's plenty of other stuff you could add but that should form the basis. In any case, you've probably got enough work ahead of you turning that into a C++ class :-)
If you don't want to roll your own solution, then Boost has a very good one that you can pretty well use as is. Boost.Bimap provides a fully-templated bi-directional map that you should be able to use with minimal code, such as the following complete program:
#include <iostream>
#include <string>
#include <boost/bimap.hpp>
using std::string;
using std::cout;
using std::exception;
using boost::bimap;
int main()
{
typedef bimap<string, int> SiMap;
typedef SiMap::value_type SiEntry;
SiMap bidi;
bidi.insert(SiEntry("ninety-nine", 99));
int i = 0;
for (string str: {"one", "two" , "three", "four", "five", "six"}) {
bidi.insert(SiEntry(str, ++i));
}
cout << "The number of entries is " << bidi.size() << "\n\n";
for (auto i = 1; i <= 7; i += 3) {
try {
cout << "Text for number " << i << " is " << bidi.right.at(i) << "\n";
} catch (exception &e) {
cout << "Got exception looking up number " << i << ": " << e.what() << "\n";
}
}
cout << "\n";
for (auto str: {"five", "ninety-nine", "zero"}) {
try {
cout << "Number for text '" << str << "' is " << bidi.left.at(str) << "\n";
} catch (exception &e) {
cout << "Got exception looking up text '" << str << "': " << e.what() << "\n";
}
}
cout << "\n";
return 0;
}
It creates a bi-directional mapping between the textual form of a number and the integral value, then does a few lookups (in both directions) to show that it works:
The number of entries is 7
Text for number 1 is one
Text for number 4 is four
Got exception looking up number 7: bimap<>: invalid key
Number for text 'five' is 5
Number for text 'ninety-nine' is 99
Got exception looking up text 'zero': bimap<>: invalid key
I do notice that this has the "stdmap" tag, so this may not be appropriate. However Boost has boost::bimap<> which will allow you to do what you want: it allows lookup by either key or value.
how to get key when input is value
First, there is no guarantee that value is unique. I realize that you are saying it is unique. Still, conceptually speaking, this is something to keep in mind when looking at the problem.
Second, std::map is not sorted by value. Hence, the most efficient algorithm to look for a value will be O(N) on an average.
Try boost Bimap. all the things you are trying to do can simply be done by it.
1 --> one
2 --> two
...
one --> 1
two --> 2
...
here is a link where a working example is present.
here
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);
The program adds different strings to a set. The iterator checks the set for a certain string, what i want to achieve is to get the line where the iterator finds this certain string. Is it possible to get this with a set or do i have to create a vector? The reason i use sets is because i also want not to have duplicates in the end. It is a bit confusing i know, i hope you'll understand.
Edit: i want to get the line number of the original element already existing in the set, if a duplicate is found
#include <iostream>
#include <set>
#include <string>
#include <vector>
#include <atlstr.h>
#include <sstream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
set<string> test;
set<string>::iterator it;
vector<int> crossproduct(9, 0);
for (int i = 0; i < 6; i++)
{
crossproduct[i] = i+1;
}
crossproduct[6] = 1;
crossproduct[7] = 2;
crossproduct[8] = 3;
for (int i = 0; i < 3; i++)
{
ostringstream cp; cp.precision(1); cp << fixed;
ostringstream cp1; cp1.precision(1); cp1 << fixed;
ostringstream cp2; cp2.precision(1); cp2 << fixed;
cp << crossproduct[i*3];
cp1 << crossproduct[i*3+1];
cp2 << crossproduct[i*3+2];
string cps(cp.str());
string cps1(cp1.str());
string cps2(cp2.str());
string cpstot = cps + " " + cps1 + " " + cps2;
cout << "cpstot: " << cpstot << endl;
it = test.find(cpstot);
if (it != test.end())
{
//Display here the line where "1 2 3" was found
cout << "i: " << i << endl;
}
test.insert(cpstot);
}
set<string>::iterator it2;
for (it2 = test.begin(); it2 != test.end(); ++it2)
{
cout << *it2 << endl;
}
cin.get();
return 0;
}
"Line number" is not very meaningful to a std::set<string>,
because as you add more strings to the set you may change the
order in which the existing strings are iterated through
(which is about as much of a "line number" as the set::set template
itself will give you).
Here's an alternative that may work better:
std::map<std::string, int> test.
The way you use this is you keep a "line counter" n somewhere.
Each time you need to put a new string cpstot in your set,
you have code like this:
std::map<std::string>::iterator it = test.find(cpstot);
if (it == test.end())
{
test[cpstot] = n;
// alternatively, test.insert(std::pair<std::string, int>(cpstot, n))
++n;
}
else
{
// this prints out the integer that was associated with cpstot in the map
std::cout << "i: " << it->second;
// Notice that we don't try to insert cpstot into the map in this case.
// It's already there, and we don't want to change its "line number",
// so there is nothing good we can accomplish by an insertion.
// It's a waste of effort to even try.
}
If you set n = 0 before you started putting any strings in test then
(and don't mess with the value of n in any other way)
then you will end up with strings at "line numbers" 0, 1, 2, etc.
in test and n will be the number of strings stored in test.
By the way, neither std::map<std::string, int>::iterator nor
std::set<std::string>::iterator is guaranteed to iterate through
the strings in the sequence in which they were first inserted.
Instead, what you'll get is the strings in whatever order the
template's comparison object puts the string values.
(I think by default you get them back in lexicographic order,
that is, "alphabetized".)
But when you store the original "line number" of each string in
std::map<std::string, int> test, when you are ready to
print out the list of strings you can copy the string-integer pairs
from test to a new object, std::map<int, std::string> output_sequence,
and now (assuming you do not override the default comparison object)
when you iterate through output_sequence you will get its
contents sorted by line number.
(You will then probably want to get the string
from the second field of the iterator.)
I am confused which is more efficient?
As we can access map directly, why do we need to use find?
I just need to know which way is more efficient.
#include <iostream>
#include <map>
using namespace std;
int main ()
{
map<char,int> mymap;
map<char,int>::iterator it;
mymap['a']=50;
mymap['b']=100;
mymap['c']=150;
mymap['d']=200;
//one way
it=mymap.find('b');
cout << (*it).second <<endl;
//another way
cout << mymap['b'] <<endl;
return 0;
}
thanks in advance! :)
Using find means that you don't inadvertently create a new element in the map if the key doesn't exist, and -- more importantly -- this means that you can use find to look up an element if all you have is a constant reference to the map.
That of course means that you should check the return value of find. Typically it goes like this:
void somewhere(const std::map<K, T> & mymap, K const & key)
{
auto it = mymap.find(key);
if (it == mymap.end()) { /* not found! */ }
else { do_something_with(it->second); }
}
As we can access map directly, why do we need to use find?
Because map<>::operator[] is sometimes nasty. If an element doesn't exist then:
it inserts it
value initialize it
returns reference of value
Thus it always returns a valid reference of value, even if a key din't exist previously. This behavior is not intended many times.
On the other hand map<>::find() is safer; because it returns end(), if a value doesn't exit. Another advantage of find() is that it returns an iterator which contains references to key (first) and value(second) both.
The [] operator in map is not constant it is logarithmic. Most of the books stress on this fact and point out it is a bit misleading. So both find and [] operator are with the same complexity.
Please note that the [] operator will create the entry even if it does not exist while find will return end() in that case.
This code and doc is picked from cplusplus.com
// accessing mapped values
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main ()
{
map<char,string> mymap;
mymap['a']="an element";
mymap['b']="another element";
mymap['c']=mymap['b'];
cout << "mymap['a'] is " << mymap['a'] << endl;
cout << "mymap['b'] is " << mymap['b'] << endl;
cout << "mymap['c'] is " << mymap['c'] << endl;
cout << "mymap['d'] is " << mymap['d'] << endl;
cout << "mymap now contains " << (int) mymap.size() << " elements." << endl;
return 0;
}
OP:
mymap['a'] is an element
mymap['b'] is another element
mymap['c'] is another element
mymap['d'] is
mymap now contains 4 elements.
Notice how the last access (to element 'd') inserts a new element in the map with that key and initialized to its default value (an empty string) even though it is accessed only to retrieve its value. Member function map::find does not produce this effect.