I have a map defined as map<string, map<string,int> > grandMap; and I need to check if the internal map has a key term. If so, count it. Here's what I tried already:
auto countOccurrences(string term) -> int
{
int count = 0;
for(auto entry : grandMap)
{
if(entry->second.find(term)!=entry->second.end())
{
count++;
cout << "counted" << endl;
}
}
return count;
}
But I get the following error(s):
415.cpp:50:11: error: base operand of '->' has non-pointer type 'std::pair<const std::basic_string<char>, std::map<std::basic_string<char>, int> >'
415.cpp:50:37: error: base operand of '->' has non-pointer type 'std::pair<const std::basic_string<char>, std::map<std::basic_string<char>, int> >'
...which clearly points to my attempt to get the second of entry, which I thought would be an element of the grandMap, but it doesn't seem to work quite how I'd like...
So what is the right way to go about this?
The problem is that you are using operator -> instead of operator .:
if (entry.second.find(term) != entry.second.end())
// ^ ^
Also, to avoid premature pessimization (see this GoTW by Herb Sutter for a definition), you should accept the term argument by reference to const, and you should also use auto const& in the range-based for loop.
Moreover, the count_if standard algorithm seems to be what you are looking for:
// Using C++14's return type deduction for regular functions...
auto count(std::string const& term)
{
return std::count_if(std::begin(grandMap), std::end(grandMap),
[&] (decltype(grandMap)::value_type const& entry)
{
return (entry.second.find("hello") != std::end(entry.second));
});
}
Here is a complete program:
#include <map>
#include <string>
#include <algorithm>
#include <iostream>
std::map<std::string, std::map<std::string, int>> grandMap =
{ { "1", { { "hello", 42 }, { "hi", 1337 } } },
{ "2", { { "hello", 42 }, { "hello", 1729 } } }};
auto count(std::string const& term)
{
return std::count_if(std::begin(grandMap), std::end(grandMap),
[&] (decltype(grandMap)::value_type const& entry)
{
return (entry.second.find("hello") != std::end(entry.second));
});
}
int main()
{
std::cout << count("hello");
}
And the corresponding live example.
Related
The essence of the program: get a map, where the values are char from the passed string, and the key is the number of these values in the string
using namespace std;
map<char, int> is_merge(const string& s) {
map<char, int> sCount {};
for (auto lp : s) {
if (find_if(sCount.begin(), sCount.end(), lp) != sCount.end()) {
sCount[lp] += 1;
} else {
sCount.insert(make_pair(lp, 0));
}
}
return sCount;
}
int main()
{
string test = "aba";
map <char, int> res = is_merge(test);
for (auto lp : res) {
cout << lp.first << ":" << lp.second << endl;
}
return 0;
}
But an error occurs in the console: /usr/include/c++/12/bits/predefined_ops.h:318:30: error: expression cannot be used as a function 318 | { return bool(_M_pred(*__it)); } | ~~~~~~~^~~~~~~
std::find_if takes a predicate not a value. Hence the error that lp is not a callable. To find a key in a map you should use std::map::find because it is O(logn) compared to O(n) for std::find/std::find_if (as a rule of thumb you can remember: If a container has a member function that does the same as a generic algorithm the member function is at least as effcient, often better).
However, there is not need to check if the key is present via find. The function can be this:
map<char, int> is_merge(const string& s) {
map<char, int> sCount {};
for (auto lp : s) {
++sCount[lp];
}
return sCount;
}
std::map::operator[] already does insert an element when none is found for the given key. You don't need to do that yourself.
PS: And if you do call insert then there is no need for std::make_pair : sCount.insert({lp, 0});. std::make_pair is for when you need to deduce the type of the pair from arguments to std::make_pair, but you don't need that here.
PPS: And if you do use std::find you need to consider that the element type of your map is std::pair<const char, int>, not char.
#include <iostream>
#include <map>
int main(void) {
std::map<char, int> mapint;
mapint.insert({'a', 1});
mapint.insert({'b', 2});
// subscript operator is overloaded to return iterator.second (the value with key 'a')
int ex = mapint['a'];
std::cout << ex << std::endl;
// Why does this NOT traslate to 1=10 ?
// instead it replaces or creates pair <'a',10>...
mapint['a'] = 10;
for (auto i : mapint) {
std::cout << i.first << "," << i.second << std::endl;
}
// OUTPUT
// 1
// a,10
// b,2
return 0;
}
How is the map operator being overloaded? I tried looking at the code for map but i couldn't find anything to answer my question...
I want to make something similar for one of my classes and i think figuring this out should help alot!
It basically just builds on top of existing methods found within map. It is implemented along the lines of...
template<typename Key, typename Value>
struct map {
// This operator cannot be declared 'const', since if the key
// is not found, a new items is automatically added.
Value& operator [] (const Key& key) {
// attempt to find the key
auto iter = find(key);
// if not found...
if(iter == end()) {
// insert new item (with a default value to start with)
iter = insert(std::make_pair(key, Value()));
}
// return reference to the data item stored for 'key'
return iter->second;
}
};
To overload the [] operator you can do as follows (in pseudo-code):
struct A
{
your_return_type operator[](your_argument_list)
{
your implementation
}
};
If you want to return a reference to some class member, then you may have to implement 2 versions of this operator, one const, which returns a non-modifiable reference, and one non-const, which returns a modifiable refence.
struct A
{
your_modifiable_return_type_ref& operator[](your_argument_list)
{
your implementation
}
const your_non_modifiable_return_type_ref& operator[](your_argument_list) const
{
your implementation
}
};
Uhm, I was writing a code to convert two strings to a bitset (unfortunately std::bitset cannot be used due to it's compile time template constant size requirement).
For some reason I cannot reference iterate for range based loop:
#include <iostream>
#include <sstream>
#include <vector>
int main()
{
std::string line;
std::getline(std::cin, line);
std::string chips;
std::string pattern;
std::istringstream issline(line);
issline >> chips;
issline >> pattern;
auto toBool = [](const char c) -> bool { return(c == 'B'); };
std::vector<bool> bitchips;
for(auto& i : chips){
bitchips.push_back(toBool(i));
}
std::vector<bool> bitpattern;
for(auto& i: pattern){
bitpattern.push_back(toBool(i));
}
auto flip = [&bitchips]() -> void
{
for(auto& i : bitchips) { //error
i = !i;
}
};
return 0;
}
error: invalid initialization of non-const reference of type 'std::_Bit_reference&' from an rvalue of type 'std::_Bit_iterator::reference {aka std::_Bit_reference}'
What program is doing so far:
Reading user input: BBBBNNNB NNNBBBNB. Converting to: 11110001 00011101
std::vector<bool> is a specialization of std::vector, it behaves different with normal std::vector. Especially, std::vector<bool>::reference is a proxy class.
proxy class representing a reference to a single bool
You might use rvalue reference instead. e.g.
auto flip = [&bitchips]() -> void
{
for(auto&& i : bitchips) {
i = !i;
}
};
or
auto flip = [&bitchips]() -> void
{
for(auto i : bitchips) {
i = !i;
}
};
or
auto flip = [&bitchips]() -> void
{
for(auto i : bitchips) {
i.flip();
}
};
even they look counterintuitive.
I'm programming in QtCreator and currently I'm using QList as shown in the following code:
#include <vector>
#include <map>
#include <algorithm>
#include <QDebug>
class mixed
{
public:
int number;
QString name;
QString address;
mixed(int n, QString s, QString a)
{
number = n;
name = s;
address = a;
}
};
bool myfunction (mixed i,mixed j) { return (i.number<j.number); }
bool mySearch (mixed i, mixed j) {
return (i.name==j.name);
}
int main()
{
QList<mixed>myV;
mixed object(100, "akkas", "100");
myV.push_back(object);
myV.push_back(mixed(2, "akkas1", "2"));
myV.push_back(mixed(1111, "akkas2", "1111"));
myV.push_back(mixed(-1, "akkas3", "-1"));
myV.push_back(mixed(7, "akkas4", "7"));
myV.push_back(mixed(0, "akkas0", "0"));
myV.push_back(mixed(2, "akkas0", "21"));
for(int i=0; i<myV.size(); i++)
{
qDebug()<<myV.at(i).number<<" "<<myV.at(i).name<<" "<<myV.at(i).address<<endl;
}
std::sort (myV.begin(), myV.end(), myfunction);
for(int i=0; i<myV.size(); i++)
{
qDebug()<<myV.at(i).number<<" "<<myV.at(i).name<<" "<<myV.at(i).address<<endl;
}
// QList<mixed>::iterator it;
// it = std::search(myV.begin(), myV.end, object, mySearch);
// if (it!=myV.end())
// qDebug() << "found at position " << (it-myV.begin()) << '\n';
// else
// qDebug() << "not found\n";
// qDebug()<<myV.indexOf(object)<<endl;
return 0;
}
But the problem is the commented out line
qDebug()<<myV.indexOf(object)<<endl;
fails because
no match for 'operator==' (operand types are 'mixed' and 'const mixed')
if (n->t() == t)
^
On the other hand I was trying to use std::search using predicate comparison where predicate is as below:
bool mySearch (mixed i, mixed j) {
return (i.name==j.name);
}
But I can't understand why it gives the error
no matching function for call to 'search(std::vector<mixed>::iterator, <unresolved overloaded function type>, mixed&, bool (&)(mixed, mixed))'
it = std::search(myV.begin(), myV.end, object, mySearch);
^
I need to use something that can allow me easy sorting using the integer value of the mixed data type and finding any element using the string value of that type.
What mistake am I doing in my approach? What alternative do I have? Could you please give me some example with code?
Thanks.
EDIT
After the responses I have corrected end to end(), but even then there are errors. Now the error is:
error: no matching function for call to 'search(QList<mixed>::iterator, QList<mixed>::iterator, mixed&, bool (&)(mixed, mixed))'
std::search(myV.begin(), myV.end(), object, mySearch);
^
qDebug()<<myV.indexOf(object)<<endl;
For this to work you need to implement == operator for class mixed. Example:
bool operator==(const mixed& rhs)
{
return name == rhs.name;
}
For second error, As rightly pointed out in the comments, you need to correct end iterator.
std::search(myV.begin(), myV.end(), object, mySearch);
^^^^^^^^
UPDATE: However this is NOT correct use of std::search. Use std::search which relies on == operator.
std::find(myV.begin(), myV.end(), object); // Uses == operator to find match
Reference: http://www.cplusplus.com/reference/algorithm/find/
This should work.
For cases like this, where your find criterion may differ from call to call, I prefer find_if: it does not force me to overload operator== for my type.
auto it = std::find_if(begin(myVec), end(myVec),
[](const auto &a, const auto &b) { return a.name == b.name; });
auto index = std::distance(begin(myVec), it);
I was wondering what the copy semantics of boost variants are. I've checked the source code and it's a bit baffling to me so I was wondering, in the example code, if my getVal(name) function makes a copy of the underlying vector when it's returned? If so, should I change it to be a reference (&) returned instead?
using Val = boost::variant<std::vector<int>, std::vector<std::string>>;
Val getVal(std::string& name) {
return map[name];// where map is std::map<std::string, Val>
}
Yes, your getVal returns a copy of the whole vectors (including copies of all the element strings, e.g.).
Yes, returning a reference instead solves this.
Note you can also have a variant that stores a reference. In this case, returning it by "value" still has the same semantics as returning the reference:
using Ref = variant<std::vector<int>&, std::vector<std::string>&>;
Ref getVal(std::string& name) {
return map[name]; // where map is std::map<std::string, Val>
}
Full sample with the necessary mechanics to convert from Ref to Val (and vice versa):
Live On Coliru
#include <boost/variant.hpp>
#include <map>
#include <vector>
#include <string>
using Val = boost::variant<std::vector<int>, std::vector<std::string>>;
using Ref = boost::variant<std::vector<int>&, std::vector<std::string>& >;
std::map<std::string, Val> map {
{ "first", std::vector<int> { 1,2,3,4 } },
{ "2nd", std::vector<std::string> { "five", "six", "seven", "eight" } }
};
namespace { // detail
template <typename T>
struct implicit_convert : boost::static_visitor<T> {
template <typename U> T operator()(U&& u) const { return std::forward<U>(u); }
};
}
Ref getVal(std::string& name) {
return boost::apply_visitor(implicit_convert<Ref>(), map[name]);
}
#include <iostream>
int main() {
for (auto i : boost::get<std::vector<int> >(map["first"])) std::cout << i << " ";
for (auto i : boost::get<std::vector<std::string> >(map["2nd"])) std::cout << i << " ";
}
Output:
1 2 3 4 five six seven eight
Without any vectors being copied