error: no match for ‘operator[]’? - c++

I am trying to access the std::map data using key, but I am getting the error
error: no match for ‘operator[]’ (operand types are ‘const std::pair’ and ‘int’)
#include <map>
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<map<int, double>> mainData;
for(int i = 0; i < 10; i++) {
map<int, double> data;
data[1] = i;
data[2] = i*2.0;
data[5] = i*7.2;
mainData.push_back(data);
}
for(auto& it1: mainData) {
for(auto& it2: it1) {
cout << it2.first << " " << it2.second << "\n";
cout << it2[5] << "\n"; // Error occurs here
}
cout << "\n";
}
return 0;
}

I think you have a typo here. I think you meant to access it1 instead of it2, because it1 is actually the map and it2 is the pair within the map.
cout << it1[5] << "\n";
Maybe you should use different variable names:
#include <map>
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<map<int, double>> mainData;
for(int i = 0; i < 10; i++) {
map<int, double> data;
data[1] = i;
data[2] = i*2.0;
data[5] = i*7.2;
mainData.push_back(data);
}
for(auto& map: mainData) {
for(auto& pair: map) {
cout << pair.first << " " << pair.second << "\n";
cout << map[5] << "\n";
}
cout << "\n";
}
return 0;
}

Maybe you meant to use it1[5]?

it2 is a std::pair (http://www.cplusplus.com/reference/utility/pair/). You meant it1[5] maybe ? Actually doing it2[x] can't work then there is a problem in the code you made

because there are no [] operator for std pair, probably you mean it1[5] instead of it2[5]

Related

c++ how to print how many times each integer appears in the STL list

using namespace std;
int main()
{
list<int> numbers; list<int> numb;
for (int i = 0; i<10; i++)
numbers.push_back(rand() % 20);
list<int>::iterator it;
for (it = numbers.begin(); it != numbers.end(); ++it)
{
cout << *it << " ";
}
return 0;
}
I wanted to use std::count() but I am not able to do it right. I tried to do the following:
using namespace std;
int main()
{
list<int> numbers; list<int> numb;
for (int i = 0; i<10; i++)
numbers.push_back(rand() % 20);
list<int>::iterator it;
for (it = numbers.begin(); it != numbers.end(); ++it)
{
cout << *it << " ";
while (it != numbers.begin() && it != numbers.end())
{
++it;
*it = count(it, numbers.begin(), numbers.end());
cout << " " << *it;
}
cout << endl;
}
return 0;
}
But it gives me an error:
binary == no operator found which takes a left hand operator type 'int' (or there is not acceptable conversion).
I know I am doing something wrong.
I also tried a few more things, like int numb = std::count(numbers.begin()), numbers.end(), *it), but it didn't work either. So, I want to know if there is a special operator to count values in a list.
You need to look at the signature for std::count again. It takes three parameters std::count(InputIterator first, InputIterator last, const T& val); and it returns the number of occurrences of val in your data set. So something like this should work for you where theNumber is the number you're counting.
#include <algorithm>
int occurrences = std::count(numbers.begin(), numbers.end(), theNumber);
You are not using iterators correctly (you are modifying it while you are still using it to iterate the list), and you are not calling std::count() correctly.
The code should look more like this instead:
#include <iostream>
#include <list>
#include <algorithm>
#include <cstdlib>
int main()
{
std::list<int> numbers;
int numb;
for (int i = 0; i < 10; i++)
numbers.push_back(std::rand() % 20);
std::list<int>::iterator it;
for (it = numbers.begin(); it != numbers.end(); ++it)
{
numb = std::count(numbers.begin(), numbers.end(), *it);
std::cout << *it << " " << numb << std::endl;
}
/* or:
for (int value : numbers)
{
numb = std::count(numbers.begin(), numbers.end(), value);
std::cout << value << " " << numb << std::endl;
}
*/
return 0;
}
But, like others said, you should use a std::map to track the counts, so you can account for duplicates, eg:
#include <iostream>
#include <list>
#include <map>
#include <cstdlib>
int main()
{
std::list<int> numbers;
std::map<int, int> numb;
for (int i = 0; i < 10; i++)
numbers.push_back(rand() % 20);
for (std::list<int>::iterator it = numbers.begin(); it != numbers.end(); ++it)
numb[*it]++;
/* or:
for (int value : numbers)
numb[value]++;
*/
for (std::map<int, int>::iterator it = numb.begin(); it != numb.end(); ++it)
std::cout << it->first << " " << it->second << std::endl;
/* or:
for (auto &item : numb)
std::cout << item.first << " " << item.second << std::endl;
*/
return 0;
}
Which can be reduced to this:
#include <iostream>
#include <map>
#include <cstdlib>
int main()
{
std::map<int, int> numb;
for (int i = 0; i < 10; i++)
numb[rand() % 20]++;
for (std::map<int, int>::iterator it = numb.begin(); it != numb.end(); ++it)
std::cout << it->first << " " << it->second << std::endl;
/* or:
for (auto &item : numb)
std::cout << item.first << " " << item.second << std::endl;
*/
return 0;
}
In general, using a map is a better approach to your problem, but if you have to solve it using lists here is one possible solution:
#include <iostream>
#include <algorithm>
#include <list>
int main()
{
std::list<int> numbers, unique_num, numb;
int num;
// Create both the original list and a list that
// will be left with only unique numbers
for (int i = 0; i<10; i++){
num = rand() % 20;
numbers.push_back(num);
unique_num.push_back(num);
}
// Sort and select the unique numbers
unique_num.sort();
unique_num.unique();
// Count unique numbers and store the count in numb
std::list<int>::iterator iter = unique_num.begin();
while (iter != unique_num.end())
numb.push_back(count(numbers.begin(), numbers.end(), *iter++));
// Print the results
for(std::list<int>::iterator iter1 = unique_num.begin(), iter2 = numb.begin();
iter2 != numb.end(); iter1++, iter2++)
std::cout<< "Number " << *iter1 << " appears " <<
*iter2 << ( *iter2 > 1 ? " times " : " time" ) << std::endl;
return 0;
}
The program uses another list, unique_num, to hold unique numbers occurring in numbers. That list is initially created identical to numbers and is then sorted and the duplicates are removed.
The program then iterates through numbers in that unique list and uses count to get the number of occurrences of each of them in the original numbers list. The number of occurrences is then stored in a new list, numb.
When printing, the program uses a ternary operator to check whether it should print "time" or "times" depending whether the result implies one or more than one occurrence.
Note - if you want different list values each time you run your program you need to change the random seed using srand. Include the header #include <time.h> in your program and the line srand(time(NULL)); at the beginning of your main.
I suggest you use a map:
map<int, int> counts;
for(int val : Numbers)
++counts[val];
WITH ADDITIONAL MEMORY:
You can use buckets, to get complexity O(N + MAX_NUM). So when MAX_NUM <= N we have O(N):
#include <iostream>
#include <list>
#include <algorithm>
#include <ctime>
const int MAX_NUM = 20;
const int N = 10;
int main() {
std::list<int> numbers;
int buckets[MAX_NUM];
std::fill(buckets, buckets + MAX_NUM, 0);
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// computing
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
buckets[*it]++;
}
//printing answers
for (int i = 0; i < MAX_NUM; i++) {
if (buckets[i]) std::cout << "value " << i << " appears in the list " << buckets[i] << " times." <<std::endl;
}
return 0;
}
For big data i would recommend using std::unordered_map for buckets and then geting complexity O(N) (thanks to hashing):
#include <iostream>
#include <list>
#include <algorithm>
#include <ctime>
#include <unordered_map>
const int N = 10;
const int MAX_NUM = 20;
int main() {
std::list<int> numbers;
std::unordered_map<int, int> buckets;
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// computing
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
buckets[*it]++;
}
//printing answers
for (auto & k_v : buckets) {
std::cout << "value " << k_v.first << " appears in the list " << k_v.second << " times." <<std::endl;
}
return 0;
}
WITHOUT ADDITIONAL MEMORY:
In more universal way, you can use std::vector instead of std::list and std::sort on it, and then count value changes in a simple for. Complexity is O(N log N):
#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
const int N = 10;
const int MAX_NUM = 20;
int main() {
std::vector<int> numbers;
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// sorting
std::sort(numbers.begin(), numbers.end());
//printing answers for sorted vector
if (numbers.size() > 0) {
int act_count = 1;
for (int i = 1; i < numbers.size(); i++) {
if (numbers[i] != numbers[i -1]) {
std::cout << "value " << numbers[i-1] << " appears in the list " << act_count << " times." <<std::endl;
act_count = 1;
} else {
act_count++;
}
}
std::cout << "value " << numbers[numbers.size() - 1] << " appears in the list " << act_count << " times." <<std::endl;
}
return 0;
}
You can also do the above on std::list, getting also O(nlogn), but can't use std::sort:
#include <iostream>
#include <list>
#include <ctime>
const int N = 10;
const int MAX_NUM = 20;
int main() {
std::list<int> numbers;
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// sorting
numbers.sort();
//printing answers for sorted list
if (!numbers.empty()) {
int act_count = 0;
auto prev = numbers.begin();
for (auto it = numbers.begin(); it != numbers.end(); it++) {
if (*it != *prev) {
std::cout << "value " << *it << " appears in the list " << act_count << " times." <<std::endl;
act_count = 1;
} else {
act_count++;
}
prev = it;
}
std::cout << "value " << *prev << " appears in the list " << act_count << " times." <<std::endl;
}
return 0;
}

how do I get sequence of 'false' in an array

I am the beginner of C++, and any help will be very appreciated.
here is the code i can run successfully:
#include <Eigen/Dense>
#include <iostream>
using namespace Eigen;
main(){
bool findIn=false;
RowVectorXd A(10);
A<<false,true,false,true,true,false,false,false,true,true;
std::cout << A << std::endl;
for (int i=0;i<A.size();i++){
if(A(i)==findIn){
std::cout << i << std::endl;
}
}
system("pause");
}
the result is {0,2,5,6,7}, and I want to design a function, the code is as follows:
int seq(bool findIn, VectorXd &resdX){
VectorXd A;
for(int i=0;i<resdX.size();i++){
if(resdX(i)==findIn){
A =A+i;
}
}
return(A);
}
I want this function to return result like that {0,2,5,6,7}.But I don`t know how to set up a array to save the result or is there a function just like 'which' in R software to produce sequence above.
Sounds like you want a vector of integers:
#include <vector>
std::vector<int> seq(bool findIn, VectorXd &resdX)
{
std::vector<int> v;
for(int i=0;i<resdX.size();i++) {
if (resdX(i) == findIn) {
v.push_back(i);
}
}
return v;
}
You can then print its contents by iterating through it:
std::vector<int> result = seq(false, A);
for (int i : result) std::cout << i << '\n';
I did not understand what are you looking for.
If you want just to print a sequence of integers indexing findIn values you might code:
void seq(bool findIn, VectorXd &resdX) { // not int
std::cout << "{ ";
for(int i=0;i<resdX.size();i++) // go inside the array
if(resdX(i)==findIn) // if you find that resdX(i) value equals findIn value
std::cout << i << " "; // print i index
std::cout << "}" << std::endl; // at the end prints a new line
}
EDIT1:
Try to adapt the following snippet:
#include <list>
...
std::list<int> seq(bool findIn, VectorXd& resdX) {
std::list<int> l;
for(int i=0; i<resdX.size(); i++) {
if (resdX(i) == findIn) {
l.push_back(i);
}
}
return l;
}
void print_seq(std::list<int> list_) {
std::cout << "{ ";
std::list<int>::iterator it = list_.begin();
for (; it != list_.end(); ++it) {
std::cout << i << " ";
}
std::cout << " }\n";
}

how to avoid copying in boost range transform

boost range transform requires const & for ranges in arguments.
#include <iostream>
#include <vector>
#include <boost/range/algorithm.hpp>
int main(int argc, char *argv[])
{
using namespace std;
vector<vector<int>> rt0(10,vector<int>(15,2));
vector<vector<int>> irt(10,vector<int>(15,5));
for(auto & i:rt0) {
for(auto& j:i) cout << j << " ";
cout << "\n";
}
cout << "\n";
for(auto & i:irt) {
for(auto& j:i) cout << j << " ";
cout << "\n";
}
boost::transform(rt0,irt,rt0.begin(),
[] (const vector<int> &t0,const vector<int> &it) {
auto tt = t0;
boost::transform(t0,it,tt.begin(), plus<int>());
return tt;
}
);
cout << "\n";
cout << "\n";
for(auto & i:rt0) {
for(auto& j:i) cout << j << " ";
cout << "\n";
}
return 0;
}
compile and run with
g++ -std=c++11 main.cc; ./a.out
if boost::transform's BinaryOperation took & instead of const & for SinglePassRange1 then i wouldn't have needed to create a copy (auto tt = t0) and just use to instead of tt. is there a way to avoid creating this copying (while still using ranges)?
link to boost range transform: http://www.boost.org/doc/libs/1_53_0/libs/range/doc/html/range/reference/algorithms/mutating/transform.html
I need to use for_each either with a tuple or the new boost implementation that takes two arguments.
conceptually transform should not modify. it comes from functional programming where there is no in-place modification.

How can I print both the key and the value in a map?

When I try to print with it.first, it.second it does not work,
Are these even valid functions?
#include <iostream>
#include <string>
#include <map>
using namespace std;
int main()
{
map<string, int> workers;
workers["John"] = 1;
workers["Frank"] = 2;
for(map<string, int>::iterator it = workers.begin(); it != workers.end(); ++it) {
cout<<it.first()<<":"<<it.second()<<endl;
}
return 0;
}
first and second are no member functions, they are plain member objects:
cout << it->first << ":" << it->second << endl;
Note no parens, those are not function calls.

Replace BOOST_FOREACH with "pure" C++11 alternative?

Is it possible to replace the BOOST_FOREACH in this example with a "pure" C++11 equivalent?
#include <map>
#include <functional>
#include <boost/foreach.hpp>
#include <iostream>
int main() {
std::map<int, std::string> map = {std::make_pair(1,"one"), std::make_pair(2,"two")};
int k;
std::string v;
BOOST_FOREACH(std::tie(k, v), map) {
std::cout << "k=" << k << " - " << v << std::endl;
}
}
The key feature being keeping the key/value pair in the references to k and v.
I tried:
for(std::tie(k,v) : map)
{
std::cout << "k=" << k << " - " << v << std::endl;
}
and
auto i = std::tie(k,v);
for(i : map)
{
std::cout << "k=" << k << " - " << v << std::endl;
}
But none of the ranged based for loop ideas seemed to work. Presumably the ranged based for loop is required to have a declaration before the :, since even:
std::vector<int> test;
int i;
for (i : test);
Isn't valid.
The closest equivalent I can find is:
for (auto it = map.begin(); it!=map.end() && (std::tie(k,v)=*it,1); ++it)
{
std::cout << "k=" << k << " - " << v << std::endl;
}
which isn't quite as succinct as the BOOST_FOREACH version!
Is there a way to express the same thing succinctly without boost in C++11?
for (auto & i : map)
{
std::tie(k,v) = i;
// your code here
}
This produces the same output as the Boost macro
for( auto const& k : map ) {
std::cout << "k = " << k.first << " - " << k.second << std::endl;
}
With C++17 this can now be done using structured bindings, for instance:
#include <map>
#include <string>
#include <iostream>
int main() {
const std::map<std::string, std::string> map = {std::make_pair("hello", "world")};
for (auto& [k,v]: map) {
std::cout << "k=" << k << ", v=" << v << "\n";
}
}
This is certainly what I'd choose to do in newer projects.