How to read from a map in C++? - c++

I have a map of std::map<int,float,float> m_mapWheelvalue; of 100 elements
I need to read the values .Code i am using is below:
float fvalue1,fvalue2;
std::map<double,float,float>::iterator itNewMap;
itNewMap= m_mapWheelvalue.find(20);
if(itNewMap!= m_mapWheelvalue.end())
{
fValue1 = itNewMap->second;
fValue2= itNewMap->third;
}
but its giving error !!{ third not defined }
How to read third value
Please give proper solution

The following compiled for me:
#include <map>
int main(){
std::map<double,std::pair<float,float> > m_mapWheelvalue;
float fValue1,fValue2;
std::map<double,std::pair<float,float> >::iterator itNewMap;
itNewMap= m_mapWheelvalue.find(20);
if(itNewMap!= m_mapWheelvalue.end()){
fValue1 = itNewMap->second.first;
fValue2= itNewMap->second.second;
}
}
Notes:
Look at std::map definition: first parameter is the key, second parameter is the entry... third parameter is the comparison function. I guess you wanted to have several values in the entry. I've chosen to use a pair (as you have two), if you have more you might want to define a struct/class.
Check variable names, there are several case changes.
The iterator to a map gets you a pair of key,entry... so itNewMap->first is the key, itNewMap->second is the entry.

Related

Name integers in a loop

I need to give these integers names like ex_number_1, ex_number_2, ex_number_3, etc... These are each going to be saved as a different branch of a tree. So I have done:
char m_variable2 [40];
For (……){
sprintf(m_variable2, "ex_number_%d",iSyst);
int m_variable2 = …
}
This is within another couple of loops, e.g. to vary iSyst. It complains about conflicting variable declarations, how do I give the integers the names of m_variable2?
I'm trying to copy what's already been done in huge chunks of the code for histograms, which are in this same loop and accept the following syntax:
hist (TString("example_"+x.at(iSyst)).Data() )->Fill (jets->at(jets.first)->phi(), weight );
But replacing hist with int does not work, and I have to use assignment not this Fill method.
It sounds like you want an associative container such as std::map or std::unordered_map.
std::map<std::string, int> numbers;
numbers["ex_number_1"] = 42;
// or with a dynamic key:
std::map<std::string, int> numbers;
for (...) {
int iSyst = ...;
numbers[std::format("ex_number_{}", iSyst)] = 69;
}
It complains about conflicting variable declarations
Simply give the array variable a different name than what you gave for the integer variable. Example:
char m_variable2_array [40];
…
int m_variable2 = …
But then the integers won't be called ex_number_1, right?
You can name the integers like that by doing this:
int ex_number_1 = …

c++ - sorting a vector of custom structs based on frequency

I need to find the most frequent element in an array of custom structs. There is no custom ID to them just matching properties.
I was thinking of sorting my vector by frequency but I have no clue how to do that.
I'm assuming by frequency you mean the number of times an identical structure appears in the array.
You probably want to make a hash function (or overload std::hash<> for your type) for your custom struct. Then iterate over your array, incrementing the value on an unordered_map<mytype, int> for every struct in the array. This will give you the frequency in the value field. Something like the below would work:
std::array<mytype> elements;
std::unordered_map<mytype, int> freq;
mytype most_frequent;
int max_frequency = 0;
for (const mytype &el : elements) {
freq[el]++;
if (freq[el] > max_frequency) {
most_frequent = el;
}
}
For this to work, the map will need to be able to create a hash for the above function. By default, it tries to use std::hash<>. You are expressly allowed by the standard to specialize this template in the standard namespace for your own types. You could do this as follows:
struct mytype {
std::string name;
double value;
};
namespace std {
template <> struct hash<mytype> {
size_t operator()(const mytype &t) const noexcept {
// Use standard library hash implementations of member variable types
return hash<string>()(t.name) ^ hash<double>()(t.value)
}
}
}
The primary goal is to ensure that any two variables that do not contain exactly the same values will generate a different hash. The above XORs the results of the standard library's hash function for each type together, which according to Mark Nelson is probably as good as the individual hashing algorithms XOR'd together. An alternative algorithm suggested by cppreference's hash reference is the Fowler-Noll-Vo hash function.
Look at std::sort and the example provided in the ref, where you actually pass your own comparator to do the trick you want (in your case, use the frequencies). Of course, a lambda function can be used too, if you wish.

Using an unordered_map with arrays as keys

I don't understand why I can't have an unordered_map with an array<int,3> as the key type:
#include <unordered_map>
using namespace std;
int main() {
array<int,3> key = {0,1,2};
unordered_map< array<int,3> , int > test;
test[key] = 2;
return 0;
}
I get a long error, the most pertinent part being
main.cpp:11:9: error: no match for ‘operator[]’ (operand types are std::unordered_map<std::array<int, 3ul>, int>’ and ‘std::array<int, 3ul>’)
test[key] = 2;
^
Are arrays not eligible to be keys because they miss some requirements?
You have to implement a hash. Hash tables depending on hashing the key, to find a bucket to put them in. C++ doesn't magically know how to hash every type, and in this particular case it doesn't know how to hash an array of 3 integers by default. You can implement a simple hash struct like this:
struct ArrayHasher {
std::size_t operator()(const std::array<int, 3>& a) const {
std::size_t h = 0;
for (auto e : a) {
h ^= std::hash<int>{}(e) + 0x9e3779b9 + (h << 6) + (h >> 2);
}
return h;
}
};
And then use it:
unordered_map< array<int,3> , int, ArrayHasher > test;
Edit: I changed the function for combining hashes from a naive xor, to the function used by boost for this purpose: http://www.boost.org/doc/libs/1_35_0/doc/html/boost/hash_combine_id241013.html. This should be robust enough to actually use.
Why?
As mentioned in http://www.cplusplus.com/reference/unordered_map/unordered_map/
Internally, the elements in the unordered_map are not sorted in any
particular order with respect to either their key or mapped values,
but organized into buckets depending on their hash values to allow for
fast access to individual elements directly by their key values (with
a constant average time complexity on average).
Now as per your question we need to hash an array which has not been implemented internally in standard c++.
How to get over with it?
So if you want to map an array to a value you must implement your own std::hash http://en.cppreference.com/w/cpp/utility/hash for which you might get some help from C++ how to insert array into hash set?.
Some work around
If you are free to use boost then it can provide you with hashing of arrays and many other types. It basically uses hash_combine method for which you can have a look at http://www.boost.org/doc/libs/1_49_0/boost/functional/hash/hash.hpp.
The relevant error is
error: no match for call to '(const std::hash<std::array<int, 3ul> >) (const std::array<int, 3ul>&)'
The unordered_map needs a hash of the key, and it looks for an overload of std::hash to do that. You can extend the namespace std with a suitable hash function.
Compiled with msvc14 gives the following error:
"The C++ Standard doesn't provide a hash for this type."
I guess this is self-explanatory.

Find in Vector of a Struct

I made the following program where there is a struct
struct data
{
int integers; //input of integers
int times; //number of times of appearance
}
and there is a vector of this struct
std::vector<data> inputs;
and then I'll get from a file an integer of current_int
std::fstream openFile("input.txt")
int current_int; //current_int is what I want to check if it's in my vector of struct (particularly in inputs.integers)
openFile >> current_int;
and I wanna check if current_int is already stored in my vector inputs.
I've tried researching about finding data in a vector and supposedly you use an iterator like this:
it = std::find(inputs.begin(),inputs.end(),current_int)
but will this work if it's in a struct? Please help.
There are two variants of find:
find() searches for a plain value. In you case you have a vector of data, so the values passed to find() should be data.
find_if() takes a predicate, and returns the first position where the predicates returns true.
Using the latter, you can easily match one field of your struct:
auto it = std::find_if(inputs.begin(), inputs.end(),
[current_int] (const data& d) {
return d.integers == current_int;
});
Note that the above uses a C++11 lambda function. Doing this in earlier versions of C++ requires you to create a functor instead.

c++ STL Map one key two values

I have a situation where I have a map with one key and two values ex.
std::map<std::string, std::pair<double, double> > myMultiValueMap
depending on a condition I need to either update one value or the other.
I'd am looking for syntax to insert/ find the key and update either values in this map
yes I have used the insert on Maps before, but was not sure on multivalue map
std::map<std::string,double> myMap;
myMap.insert(std::make_pair("12345",0.00));
and find and update too
std::map<std::string,double>::iterator it = myMap.find(("12345");
std::map requires two template arguments, one key and one value type. But it is up to you to use arbitrary type for "value".
struct TestValue {
int Value1;
int Value2;
int Value3;
TestValue(int v1, int v2, int v3) : Value1(v1), Value2(v2), Value3(v3) {}
};
std::map<std::string, TestValue> myMap;
myMap["test"] = TestValue(1, 2, 3);
Inserting an item into the map:
myMultiValueMap[strKey] = make_pair(firstDouble, secondDouble);
Checking if an item exists:
if( myMultiValueMap.find(strKey) != myMultiValueMap.end() ) {
// Item Exists
}
Updating an item:
myMultiValueMap[strKey].first = newFirstDouble;
myMultiValueMap[strKey].second = newSecondDouble;
You should use this for these to work
using namespace std;
Please take time and read the examples from cplusplus.com
I like bkausbk's answer and would have commented on the answer but don't have rep. Map sometimes has a problem with needing a default constructor. I know this from another SO post. I got it to work by setting default arguments (the post has other solutions)
So I changed the constructor in bkausbk's answer to:
TestValue(int v1 = 0, int v2 = 0, int v3 = 0) : Value1(v1), Value2(v2), Value3(v3) {}