Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Iterating over an enum (or not)

9,983 views
Skip to first unread message

nw

unread,
Feb 6, 2008, 11:28:30 AM2/6/08
to
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.

Christopher Swiedler

unread,
Feb 6, 2008, 10:43:02 PM2/6/08
to
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

nw

unread,
Feb 7, 2008, 4:20:02 AM2/7/08
to
> 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:

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

James Kanze

unread,
Feb 7, 2008, 10:23:21 AM2/7/08
to
On Feb 6, 5:28 pm, nw <n...@soton.ac.uk> wrote:
> 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 ) {
// ...
}

--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

0 new messages