Reputation: 2341
i would like to check an array for a specific range of values. ie, the range of values is from 0 --> 9 and the actual array is 50 elements large.
i also want to keep track of how many of each value there is. ie, if there are 3 zeroes, 8 ones and 5 two's, then my final vector should look like, 3 8 5.
i was able to solve it with the code below BUT, i realized that my range values needs to be equal to my array size, otherwise it does not 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;
}
Upvotes: 3
Views: 6102
Reputation: 39089
If you have large enough empty regions, you can try a multiset, together with some of C++' new facilities:
#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, a std::vector
might give superiour 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';
}
Upvotes: 0
Reputation: 24133
Use a std::map
and the std::accumulate
function:
#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);
Upvotes: 0
Reputation: 59811
If your range is continuous I would prefer a 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 at 0
you can use IndexMap
template
argument to remap the indices. This will also work if you map a non
continous set of values that you want to count into a continous
range. You might need to perform a check if you only want to count
specific values, but given the expensiveness of the count operation,
I'd rather count them all instead of checking what to count.
Upvotes: 0
Reputation: 132
It's 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 don't save unused values and the loop count is also much smaller, because you only process once per value.
Upvotes: 4