C ++ checking an array for a specific range of values?
I would like to check an array for a specific range of values. those. the range of values โโis 0 to> 9, and the actual array is 50 elements.
I also want to keep track of how much of each value is there. those. if there are 3 zeros, 8 ones and 5 two, then my last vector should look like this: 3 8 5.
i was able to solve it with below code BUT, i figured out that my range values โโmust be equal to the size of my array, otherwise it doesn't check all elements.
Is there a better way to do this?
int main() {
int intensityRange = 10;
int cloudSize = 10;
int cloud [] = {0, 3, 3, 2, 1, 5, 2, 3, 5, 2};
vector <int> totalGreyValues;
int k = 0;
for (int i = 0; i < intensityRange; i++) {
for (int j = 0; j < cloudSize; j++) {
if (cloud[j] == i) {
k = k + 1;
cout << " " << k;
}
else
cout << " no match ";
}
totalGreyValues.push_back (k);
k = 0;
}
cout << endl << endl << totalGreyValues.size();
for (int h = 0; h < totalGreyValues.size(); h ++)
cout << " " << totalGreyValues[h];
// values --> 0 1 2 3 4 5 6 7 8 9
// answer --> 1 1 3 3 0 2 0 0 0 0
return 0;
}
source to share
Much easier to use std::map
:
int size = 50;
int data[size] = { 1, 2, 3, 4, 5, ... };
std::map<int, int> mymap;
for(int i = 0; i < size; i++)
{
if(data[i] >= min && data[i] <= max)
mymap[data[i]] = mymap[data[i]] + 1;
}
This saves some space because you are not saving unused values, and the number of loops is also much less because you only process once per value.
source to share
If your range is contiguous, I would prefer boost :: vector_property_map .
#include <boost/property_map/vector_property_map.hpp>
#include <iostream>
int main()
{
boost::vector_property_map<unsigned int> m(10); // size of expected range
std::vector<int> cloud = {0, 3, 3, 2, 1, 5, 2, 3, 5, 2};
for(auto x : cloud) { m[x]++; }
for(auto it = m.storage_begin(); it != m.storage_end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
If your range does not start with 0
, you can use the template IndexMap
argument to reassign the indices. This will also work if you are a continuous set of values โโthat you want to convert to a continuous assortment. You may need to do a check if you only want to count but given the high cost of counting operations, I would rather count them all rather than check what to count.
source to share
Use a function std::map
and std::accumulate
:
#include <map>
#include <algorithm>
typedef std::map<int, int> Histogram;
Histogram& addIfInRange(Histogram& histogram, const int value)
{
if(inRange(value))
{
++histogram[value];
}
// else don't add it
return histogram;
}
Histogram histogram =
std::accumulate(data, data + size, Histogram(), addIfInRange);
source to share
If you have enough free scopes, you can try the multiset along with some new C ++ features:
#include <set>
#include <iostream>
int main () {
int vals[] = { 0, 1, 2, 3, 4, 5, 5, 5, 6 };
std::multiset <int> hist;
for (auto const &v : vals)
if (v >= 3 && v <= 5) hist.insert (v);
for (auto const &v : hist)
std::cout << v << " -> " << hist.count (v) << '\n';
}
If your data is densely populated, std::vector
may give better results:
#include <algorithm>
#include <iostream>
int main () {
using std::begin; using std::end;
int vals[] = { 1, 2, 4, 5, 5, 5, 6 };
const auto val_mm = std::minmax_element (begin(vals), end(vals));
const int val_min = *val_mm.first,
val_max = *val_mm.second + 1;
std::vector<int> hist (val_max - val_min);
for (auto v : vals)
++hist [v - val_min];
for (auto v : vals)
std::cout << v << " -> " << hist[v-val_min] << '\n';
}
source to share