Iterating over an enum (or not)

N

nw

Hi,

I have the following class:

class ReadIntensity {
public:
enum Base_Type {
base_a,base_c,base_g,base_t,base_invalid
};

ReadIntensity() : bases(base_count) {
}

/// No bounds checking!
inline double getbase(Base_Type position) const {
return bases[position];
}

/// No bounds checking!
inline void setbase(Base_Type position,double value) {
bases[position] = value;
}

const static int base_count = 4;
vector<double> bases;
};

I'm choosing to use an enum here because I feel it represents my
problem well. Sometimes I want to access my bases though name, other
times I'd like to be able to enumerate over the enum. However
iterating over the enum seems messy for example:

#include <vector>
#include <iostream>

using namespace std;

int main() {
ReadIntensity r;

r.setbase(ReadIntensity::base_a, 5.5);
r.setbase(ReadIntensity::base_t, 5.6);
r.setbase(ReadIntensity::base_g, 5.7);
r.setbase(ReadIntensity::base_c, 5.8);

double sum=0;
ReadIntensity::Base_Type i;
for(i = ReadIntensity::base_a;i <
ReadIntensity::base_invalid;i=ReadIntensity::Base_Type (i+1)) {
sum += r.getbase(i);
}

cout << sum << endl;
}

Where I'm basically having to hard code in the ends of my enum. Is
there a better way of attacking this problem?
For example would this be a better solution?

#include <vector>
#include <iostream>

using namespace std;

class ReadIntensity {
public:
static const int base_a = 0;
static const int base_c = 1;
static const int base_g = 2;
static const int base_t = 3;
static const int base_invalid = 4;
static const int num_bases = 5;

ReadIntensity() : bases(num_bases-1) {
}

/// No bounds checking!
inline double getbase(int position) const {
return bases[position];
}

/// No bounds checking!
inline void setbase(int position,double value) {
bases[position] = value;
}

vector<double> bases;
};

int main() {
ReadIntensity r;

r.setbase(ReadIntensity::base_a, 5.5);
r.setbase(ReadIntensity::base_t, 5.6);
r.setbase(ReadIntensity::base_g, 5.7);
r.setbase(ReadIntensity::base_c, 5.8);

double sum=0;
int i;
for(i = 0;i < ReadIntensity::num_bases;i++) {
sum += r.getbase(i);
}

cout << sum << endl;
}

Suggestions and general comments appreciated.
 
C

Christopher Swiedler

I recommend keeping a std::map<BaseType, double> inside the
ReadIntensity class and using it to store the bases and values. You
can iterate over the contents of the map in BaseType order, or you can
look up the value of a particular BaseType. Both are efficient and
easy enough to do. Something like this:

typedef enum { base_a,base_c,base_g,base_t,base_invalid } BaseType;

typedef std::map<BaseType, double> BaseMap;

class ReadIntensity
{
public:
...

BaseMap m_BaseMap;
};

ReadIntensity r;
r.m_BaseMap[base_a] = 5.0;
r.m_BaseMap[base_t] = 5.0;
r.m_BaseMap[base_g] = 5.0;
r.m_BaseMap[base_c] = 5.0;

double sum = 0;
for (BaseMap::iterator i = r.m_BaseMap.begin(); i !=
r.m_BaseMap.end(); ++i)
{
double value = i->second;
sum += value;
}

double base_a_value = r.m_BaseMap[base_a];

Be careful when using operator[] with a map, since if the key/value
doesn't exist it will be created (with a default value), inserted into
the map, and returned.

chris
 
N

nw

I recommend keeping a std::map said:
ReadIntensity class and using it to store the bases and values. You
can iterate over the contents of the map in BaseType order, or you can
look up the value of a particular BaseType. Both are efficient and
easy enough to do. Something like this:

Map has poor time complexity when accessing objects O(log n) compared
to vector O(1), I'd like to avoid this if possible.
 
J

James Kanze

I have the following class:
class ReadIntensity {
public:
enum Base_Type {
base_a,base_c,base_g,base_t,base_invalid
};

[...]
I'm choosing to use an enum here because I feel it represents
my problem well. Sometimes I want to access my bases though
name, other times I'd like to be able to enumerate over the
enum. However iterating over the enum seems messy for example:


[...]
ReadIntensity::Base_Type i;
for(i = ReadIntensity::base_a;i <
ReadIntensity::base_invalid;i=ReadIntensity::Base_Type (i+1)) {
sum += r.getbase(i);
}

The solution I'd adopt is to create an iterator for the enum.
Within the iterator, you can maintain the value in an unsigned,
or whatever, but just arrange for the operator* to return it
cast to your enum type.

You can also overload the ++ and -- on the enum type; in your
case, since you have an explicit invalid value at the end, this
works beautifully, but when you don't, you have the awkward
situation of not being able to spedify a good top limit for the
half open range. So just write something like:

ReadIntensity::Base_Type&
operator++( ReadIntensity::Base_Type& target )
{
target = static_cast< ReadIntensity::Base_Type >(
target + 1 ) ;
return target ;
}

and then:

for ( ReadIntensity::Base_Type i = ReadIntensity::base_a ;
i != ReadIntensity::base_invalid ;
++ i ) {
// ...
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top