I want to search if the pair exists in the vector of pairs using binary search.
Here is my code: This code is only looking for the first value in pair:
Could you modify this code that it will be looking for the exact pair?
#include <bits/stdc++.h>
using namespace std;
struct compare {
bool operator()(const pair<int, int>& value,
const int& key)
{
return (value.first < key);
}
bool operator()(const int& key,
const pair<int, int>& value)
{
return (key < value.first);
}
};
int main()
{
vector<pair<int, int> > vect;
vect.push_back(make_pair(1, 20));
vect.push_back(make_pair(3, 42));
vect.push_back(make_pair(4, 36));
vect.push_back(make_pair(2, 80));
vect.push_back(make_pair(7, 50));
vect.push_back(make_pair(9, 20));
vect.push_back(make_pair(3, 29));
sort(vect.begin(), vect.end());
// printing the sorted vector
cout << "KEY" << '\t' << "ELEMENT" << endl;
for (pair<int, int>& x : vect)
cout << x.first << '\t' << x.second << endl;
// searching for the key element 3
cout << "search for key 3 in vector" << endl;
if (binary_search(vect.begin(), vect.end(),
3, compare()))
cout << "Element found";
else
cout << "Element not found";
return 0;
}
If you want to look for an exact pair, you need to provide the pair to binary_search, like this
if (std::binary_search(vect.begin(), vect.end(), std::pair{3, 42}))
// ... found
Note that you don't need the custom compare function here. The default comparator does the right thing. (In fact, you should use the same comparator as used to sort the elements in the first place, otherwise binary_search will be broken).
Note that pre c++17, you need to provide the template arguments to pair, like this,
if (std::binary_search(vect.begin(), vect.end(), std::pair<int,int>{3, 42}))
// ... found
If you want to find the position of the found element, you can use lower_bound like so,
auto lb = std::lower_bound(vect.begin(), vect.end(), std::pair<int,int>{3, 42});
if (lb != vect.end())
std::cout << "Element found at position "
<< std::distance(vect.begin(), lb);
Also, please don't use #include <bits/stdc++.h> or using namespace std;
Related
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);
#include <iostream>
using namespace std;
void insertValue(map<string, set<string> >& myMap,
string const& key,
string const& value)
{
// Check whether there is already a set given the key.
// If so, insert to the existing set.
// Otherwise, create a set and add it to the map.
map<string, set<string> >::iterator found = myMap.find(key);
if (found != myMap.end())
{
cout << "Adding '" << value << "' to an existing set of " << key << "s.\n";
found->second.insert(value);
}
else
{
cout << "Adding '" << value << "' to a new set of " << key << "s.\n";
set<string> temp;
temp.insert(value);
myMap.insert(make_pair(key, temp));
}
}
int main()
{
map<string, set<string> > filemap;
insertValue(mymap, "file1", "path1");
insertValue(mymap, "file1", "path2");
insertValue(mymap, "file1", "path3");
insertValue(mymap, "file2", "path1");
insertValue(mymap, "file3", "path2");
return 0;
}
Can anyone tell me how I can iterate through the set of strings, given a key in the above map???? or do I have to place an iterator in the value ....I can't understand how can I go this this further
The easiest way to iterate over the map is by using a range-based for instead of using iterators
for(auto const& kv : mymap) {
for(auto const& v : kv.second) {
std::cout << kv.first << ": " << v << '\n';
}
}
kv is a const& to your map's value_type, which is std::pair<const std::string, std::set<std::string>>. The nested for statement is then iterating over the second element in the pair.
And if you really want to use iterators, then use this
for(auto miter = mymap.cbegin(); miter != mymap.cend(); ++miter) {
for(auto siter = miter->second.cbegin(); siter != miter->second.cend(); ++siter) {
std::cout << miter->first << ": " << *siter << '\n';
}
}
That aside, your function for inserting values can be simplified quite a bit. There's no need to check whether an element already exists in a map before inserting a value because map::operator[] will construct the key you pass to it if one doesn't already exist, and the corresponding value type will be value initialized. So your insertValue function becomes a one-liner.
void insertValue(map<string, set<string> >& myMap,
string const& key,
string const& value)
{
myMap[key].insert(value); // default construct a set for a new key
}
Finally, unless you need the values corresponding to a key be ordered, you can use a multimap instead. This container is just like a map, but you can have several values corresponding to a single key value. However, unlike your solution, the order of the values which have identical keys is the order of their insertion.
Live demo
I have vector of pairs where first in pair is id and second is year of study
like
vector< pairs<uint64_t, int>> students;
How to make lambda to extract all ids which belongs to year for example 1, 3, 5 ?
I solved this through iteration but I wonder if I can in c++11 make this simpler.
You can use the algorithm std::copy_if to copy elements to another container, if they match a certain criteria.
using entry = std::pair<uint64_t, int>;
std::vector<entry> result;
std::copy_if(students.begin(), students.end(), std::back_inserter(result),
[](const entry& e) { return e.second == 1; });
I've included two approaches.
The first one uses for_each with a lambda which uses a regular if statement to find specific keys. copy_if is a good substitute if that's what you want to do with your findings. It has the same approach as for_each.
The second approach uses an unordered_map to enable associative (fast) lookup with keys.
With the information you gave it sounds like you should go with the map approach. Don't overcomplicate things.
#include <iostream>
#include <utility>
#include <vector>
#include <unordered_map>
using namespace std;
int main(int argc, char *argv[]) {
vector< pair<int, int>> v;
v.emplace_back(1,2);
v.emplace_back(3,4);
v.emplace_back(5,6);
for_each(v.begin(), v.end(),[](pair<int,int> p) {
cout << "checking key " << p.first << endl;
if (p.first == 1 || p.first == 5) { // look for key 1 and 5
cout << " found a key I was looking for: "
<< p.first << "," << p.second << endl;
}
});
unordered_map<int,int> m;
m.emplace(1,2);
m.insert(make_pair(3,4));
m.insert(make_pair(5,10));
cout << "value for key 5 is: " << m[5] << endl;
}
The multimap in C++ seems to work really odd, i would like to know why
#include <iostream>
#include <unordered_map>
using namespace std;
typedef unordered_multimap<char,int> MyMap;
int main(int argc, char **argv)
{
MyMap map;
map.insert(MyMap::value_type('a', 1));
map.insert(MyMap::value_type('b', 2));
map.insert(MyMap::value_type('c', 3));
map.insert(MyMap::value_type('d', 4));
map.insert(MyMap::value_type('a', 7));
map.insert(MyMap::value_type('b', 18));
for(auto it = map.begin(); it != map.end(); it++) {
cout << it->first << '\t';
cout << it->second << endl;
}
cout << "all values to a" << endl;
for(auto it = map.find('a'); it != map.end(); it++) {
cout << it->first << '\t' << it->second << endl;
}
}
this is the output:
c 3
d 4
a 1
a 7
b 2
b 18
all values to a
a 1
a 7
b 2
b 18
why does the output still contain anything with b as the key when I am explicitly asking for 'a'? Is this a compiler or stl bug?
find, as implemented, returns an iterator for the first element which matches the key in the multimap (as with any other map). You're likely looking for equal_range:
// Finds a range containing all elements whose key is k.
// pair<iterator, iterator> equal_range(const key_type& k)
auto its = map.equal_range('a');
for (auto it = its.first; it != its.second; ++it) {
cout << it->first << '\t' << it->second << endl;
}
That's not a bug, it is by design. find returns an iterator to one of the matching elements, that's all. You'll iterate to the end of the map with your construct.
You need to use multimap::equal_range to do what you are after.
There is an Example in www.cplusplus.com , about How to use equal_range method to get all elements having the same key.
// unordered_multimap::equal_range
#include <iostream>
#include <string>
#include <unordered_map>
#include <algorithm>
typedef std::unordered_multimap<std::string,std::string> stringmap;
int main ()
{
stringmap myumm = {
{"orange","FL"},
{"strawberry","LA"},
{"strawberry","OK"},
{"pumpkin","NH"}
};
std::cout << "Entries with strawberry:";
auto range = myumm.equal_range("strawberry");
for_each (
range.first,
range.second,
[](stringmap::value_type& x){std::cout << " " << x.second;}
);
return 0;
}
Please reference the link : http://www.cplusplus.com/reference/unordered_map/unordered_multimap/equal_range/
It would seem that you get an iterator into the full "list" of pairs, starting at the first pair with 'a' as it's key. So when you iterate to the end, naturally you will get everything beyond 'a' as well. If you sought for 'c', you would probably iterate through the entire "list" doing what you do there. Perhaps you should iterate to "it != map.end() && it->first == 'a'" if you want all the a's.