Alternative STL Structure?

M

Mike Copeland

I have the following data structure that is currently processed by an
STL map.
Although it currently works for most storage and retrieval, I have
need to process the data in different orders than the map key (teamName,
teamTypeCode). Knowing that I can't "resort" the data in an STL map, is
there another STL structure that I could use to store, sort, retrieve
and process the data defined in this structure? TIA
(Please don't criticize my naming conventions - I'm old and I prefer
this nomenclature...)

struct TEAMMAPTYPE
{ // Team Ids, Names
string teamCode; // Team Code (map key)
string teamName; // Team's Name
bool isAdded; // Added flag
char teamTypeCode; // Team type Code
int teamMembers1; // Count of Team Members-1
int teamMembers2; // Count of Team Members-2
} extern teamWork; // storage for Team info
typedef map<string, TEAMMAPTYPE> TEAMS;
TEAMS teamMap;
map<string, TEAMMAPTYPE>::iterator teamIt;
 
M

Mike Copeland

typedef map<string, TEAMS::iterator> team_name_view_t;

I don't know what this does for me, insofar as sorting and accessing
in non-key order. Please explain.
Also your naming convention is sucky yes; most people use ALLCAPS for
macros only.

<sigh>, Yes, but I program only for myself, and this is what works
for me. I'm 70+ years old, and I have over a million lines of code to
support - adopting a "more reasonable" standard isn't "reasonable"...
8<{{
 
M

Mike Copeland

You would copy TEAMS iterators to the second map keying off one of the
other TEAMMAPTYPE members (teamName in my example); you would then have
to keep the two map objects in sync (deleting from both for example).

I'm missing something (still). Your code line seems to be a typedef
for a 2nd iterator that could be used to add to and reference TEAMS
objects that I _add_ to the data I've populated with the teamCode
values. I don't see a "second map", nor do I understand your "two map
objects" point.
Are you suggesting that having two iterators for the same map data
allows me to populate the map with a 2nd "set" of objects that use a
different key value (such as teamName)? If so, do I infer that by using
the 2nd iterator to store the second set I will use that iterator to
only access those objects? How so?
Please explain. 8<}}
 
M

Martin B.

I have the following data structure that is currently processed by an
STL map.
Although it currently works for most storage and retrieval, I have
need to process the data in different orders than the map key (teamName,
teamTypeCode). Knowing that I can't "resort" the data in an STL map, is
there another STL structure that I could use to store, sort, retrieve
and process the data defined in this structure? TIA

Have you considered boost::multi_index?

http://www.boost.org/doc/libs/release/libs/multi_index
> The Boost Multi-index Containers Library
> provides a class template named multi_index_container
> which enables the construction of containers maintaining
> one or more indices with different sorting
> and access semantics. [...]
br,
Martin



(Please don't criticize my naming conventions - I'm old and I prefer
this nomenclature...)

struct TEAMMAPTYPE
{ // Team Ids, Names
string teamCode; // Team Code (map key)
string teamName; // Team's Name
bool isAdded; // Added flag
char teamTypeCode; // Team type Code
int teamMembers1; // Count of Team Members-1
int teamMembers2; // Count of Team Members-2
} extern teamWork; // storage for Team info
typedef map<string, TEAMMAPTYPE> TEAMS;
TEAMS teamMap;
map<string, TEAMMAPTYPE>::iterator teamIt;
 
J

James Kanze

I have the following data structure that is currently processed by an
STL map.
Although it currently works for most storage and retrieval, I have
need to process the data in different orders than the map key (teamName,
teamTypeCode). Knowing that I can't "resort" the data in an STL map, is
there another STL structure that I could use to store, sort, retrieve
and process the data defined in this structure? TIA
(Please don't criticize my naming conventions - I'm old and I prefer
this nomenclature...)
struct TEAMMAPTYPE
{ // Team Ids, Names
string teamCode; // Team Code (map key)
string teamName; // Team's Name
bool isAdded; // Added flag
char teamTypeCode; // Team type Code
int teamMembers1; // Count of Team Members-1
int teamMembers2; // Count of Team Members-2} extern teamWork; // storage for Team info

typedef map<string, TEAMMAPTYPE> TEAMS;
TEAMS teamMap;
map<string, TEAMMAPTYPE>::iterator teamIt;

In addition to the other suggestions... Have you considered
using several std::set<TEAMMAPTYPE*,Compare>, with different
Compare?
 
M

Mike Copeland

In addition to the other suggestions... Have you considered
using several std::set<TEAMMAPTYPE*,Compare>, with different
Compare?

No, and I don't know what that is. How would it help me, and how
would it work? I need to access that stiructure's data is several
different orders (teamCode, teamName, teamTypeCode), but the map objects
are available to me only in the teamCode fields order. Please explain
how the std::set could achieve this. TIA
 
I

Ian Collins

@d8g2000yqf.googlegroups.com>, (e-mail address removed) says...

No, and I don't know what that is. How would it help me, and how
would it work? I need to access that stiructure's data is several
different orders (teamCode, teamName, teamTypeCode), but the map objects
are available to me only in the teamCode fields order. Please explain
how the std::set could achieve this. TIA

What James is suggesting is a group of sets with different sorting
orders. All you have to do is declare the comparison objects. For
example (untested):

struct ByTeamName
{
bool operator()( const TEAMMAPTYPE& lhs, const TEAMMAPTYPE& rhs )
{
return lhs.teamName < lhs.teamName;
}
};

std::set<TEAMMAPTYPE*,ByTeamName> teamsByTeamName;

Man I hate those all caps types!
 
F

Francesco

What James is suggesting is a group of sets with different sorting
orders.  All you have to do is declare the comparison objects.  For
example (untested):

struct ByTeamName
{
   bool operator()( const TEAMMAPTYPE& lhs, const TEAMMAPTYPE& rhs )
   {
     return lhs.teamName < lhs.teamName;
   }

};

std::set<TEAMMAPTYPE*,ByTeamName> teamsByTeamName;

Man I hate those all caps types!

Hi,
Just to expand on what the others have already said, here's a full
example.
And ... all my respect to a 70+ programmer. :)
Francesco

// CODE

#include <set>
#include <iostream>
#include <iomanip>

//----------------------------------------------------------------------

class CData
{
public:
int m1;
int m2;
int m3;

bool operator<( CData const & inObj ) const
{ return m1 < inObj.m1; }
};

std::eek:stream & operator<<( std::eek:stream & inStream,
CData const & inData )
{
return inStream << std::setw( 4 ) << inData.m1 << " "
<< std::setw( 4 ) << inData.m2 << " "
<< std::setw( 4 ) << inData.m3 << std::endl;
}

typedef std::multiset< CData > CMasterSet;
typedef CMasterSet::iterator CMasterIter;

//----------------------------------------------------------------------

template< typename T, T CData::*KPtr >
struct CIterComp
{
bool operator()( CMasterIter const & in1,
CMasterIter const & in2 ) const
{ return ( ( *in1 ).*KPtr ) < ( ( *in2 ).*KPtr ); }
};

typedef std::multiset< CMasterIter,
CIterComp< int, &CData::m2 > > CSlaveSet2;
typedef std::multiset< CMasterIter,
CIterComp< int, &CData::m3 > > CSlaveSet3;

//----------------------------------------------------------------------

int main()
{
CMasterSet masterSet;
CSlaveSet2 slaveSet2;
CSlaveSet3 slaveSet3;

// POPULATE
for( int c = 0; c < 15; ++c )
{
CData data;
data.m1 = static_cast< double >( rand() ) / RAND_MAX * 20;
data.m2 = static_cast< double >( rand() ) / RAND_MAX * 20;
data.m3 = static_cast< double >( rand() ) / RAND_MAX * 20;
CMasterIter iter = masterSet.insert( data );
slaveSet2.insert( iter );
slaveSet3.insert( iter );
}

// WHEN ERASING
{
CData dummy;
dummy.m1 = 10;
CMasterIter iter = masterSet.lower_bound( dummy );
// ERASE FIRST FROM SLAVE SETS OR UB...
slaveSet2.erase( iter );
slaveSet3.erase( iter );
masterSet.erase( iter );
}

// DEFAULT ORDERING
for( CMasterIter iter = masterSet.begin();
iter != masterSet.end(); ++iter )
std::cout << *iter;

std::cout << std::string( 20, '-' ) << std::endl;

// SECOND ORDERING
for( CSlaveSet2::iterator iter = slaveSet2.begin();
iter != slaveSet2.end(); ++iter )
std::cout << **iter;

std::cout << std::string( 20, '-' ) << std::endl;

// THIRD ORDERING
for( CSlaveSet3::iterator iter = slaveSet3.begin();
iter != slaveSet3.end(); ++iter )
std::cout << **iter;
}

// END CODE
 
F

Francesco

What James is suggesting is a group of sets with different sorting
orders.  All you have to do is declare the comparison objects.  For
example (untested):

struct ByTeamName
{
   bool operator()( const TEAMMAPTYPE& lhs, const TEAMMAPTYPE& rhs )
   {
     return lhs.teamName < lhs.teamName;
   }

};

std::set<TEAMMAPTYPE*,ByTeamName> teamsByTeamName;

Man I hate those all caps types!

Hi again,
the example I posted before had a tricky problem. Corrected.
Hope it helps.
Francesco

// CODE

#include <set>
#include <iostream>
#include <iomanip>

//----------------------------------------------------------------------

class CData
{
public:
int m1;
int m2;
int m3;

// normal "full" ordering
// notice m3 is not taken into account
bool operator<( CData const & inObj ) const
{ return m1 < inObj.m1 ? true :
inObj.m1 < m1 ? false :
m2 < inObj.m2 ? true : false; }
};

std::eek:stream & operator<<( std::eek:stream & inStream,
CData const & inData )
{
return inStream << std::setw( 4 ) << inData.m1 << " "
<< std::setw( 4 ) << inData.m2 << " "
<< std::setw( 4 ) << inData.m3 << std::endl;
}

typedef std::multiset< CData > CMasterSet;
typedef CMasterSet::iterator CMasterIter;

//----------------------------------------------------------------------

template< typename T, T CData::*KPtr >
struct CIterComp
{
// custom ordering giving priority to one member
// then taking into account normal ordering
bool operator()( CMasterIter const & in1,
CMasterIter const & in2 ) const
{ return ( ( *in1 ).*KPtr ) < ( ( *in2 ).*KPtr ) ? true :
( ( *in2 ).*KPtr ) < ( ( *in1 ).*KPtr ) ? false :
*in1 < *in2; }
};

typedef std::multiset< CMasterIter,
CIterComp< int, &CData::m2 > >
CSlaveSet2;
typedef std::multiset< CMasterIter,
CIterComp< int, &CData::m3 > >
CSlaveSet3;

//----------------------------------------------------------------------

int main()
{
CMasterSet masterSet;
CSlaveSet2 slaveSet2;
CSlaveSet3 slaveSet3;

// populate
for( int c = 0; c < 15; ++c )
{
CData data;
data.m1 = static_cast< double >( rand() ) / RAND_MAX * 20;
data.m2 = static_cast< double >( rand() ) / RAND_MAX * 20;
data.m3 = static_cast< double >( rand() ) / RAND_MAX * 20;
CMasterIter iter = masterSet.insert( data );
slaveSet2.insert( iter );
slaveSet3.insert( iter );
}

// erasing is tricky
{
CData dummy;
dummy.m1 = 10;
CMasterIter iter = masterSet.lower_bound( dummy );
// suppose you have an iterator into the master set
// you want to erase THAT item from all sets
// doing slaveSet2.erase( iter ) might not do what you want
// while std::find will use equality comparison
// between iterators
// ah... erase first from slaves or else... UB
slaveSet2.erase(
std::find( slaveSet2.lower_bound( iter ),
slaveSet2.end(), iter ) );
slaveSet3.erase(
std::find( slaveSet3.lower_bound( iter ),
slaveSet3.end(), iter ) );
masterSet.erase( iter );
}

// DEFAULT ORDERING
for( CMasterIter iter = masterSet.begin();
iter != masterSet.end(); ++iter )
std::cout << *iter;

std::cout << std::string( 20, '-' ) << std::endl;

// SECOND ORDERING
for( CSlaveSet2::iterator iter = slaveSet2.begin();
iter != slaveSet2.end(); ++iter )
std::cout << **iter;

std::cout << std::string( 20, '-' ) << std::endl;

// THIRD ORDERING
for( CSlaveSet3::iterator iter = slaveSet3.begin();
iter != slaveSet3.end(); ++iter )
std::cout << **iter;
}

// END CODE
 
M

Mike Copeland

The code you posted for me doesn't compile (VS6.0), and I don't know
what to do to move forward with your help. Specifically, the main
errors (there are 13) are highlighted with comments before the code.
Please advise. TIA
// CODE
#pragma warning (disable:4786) // I added this line
#include <set>
#include <iostream>
#include <iomanip>
//----------------------------------------------------------------------
class CData
{
public:
int m1;
int m2;
int m3;
// normal "full" ordering; notice m3 is not taken into account
bool operator<(CData const & inObj) const
{
return m1 < inObj.m1 ? true : inObj.m1 < m1 ? false :
m2 < inObj.m2 ? true : false;
}
};

std::eek:stream & operator<<(std::eek:stream & inStream, CData const & inData)
{
return inStream << std::setw(4) << inData.m1 << " "
<< std::setw(4) << inData.m2 << " "
<< std::setw(4) << inData.m3 << std::endl;
}

typedef std::multiset<CData> CMasterSet;
typedef CMasterSet::iterator CMasterIter;
//----------------------------------------------------------------------
template< typename T, T CData::*KPtr >
struct CIterComp
{
// custom ordering giving priority to one member
// then taking into account normal ordering
bool operator()(CMasterIter const & in1, CMasterIter const & in2)
const
{ return ((*in1).*KPtr) < ((*in2).*KPtr) ? true :
((*in2).*KPtr) < ((*in1).*KPtr) ? false :
*in1 < *in2;
}
};
//////////////////////////////////////////////////////////
// Errors below:
// error C2964: invalid expression as template parameter
//////////////////////////////////////////////////////////
typedef std::multiset< CMasterIter,
CIterComp< int, &CData::m2 > > CSlaveSet2;
typedef std::multiset< CMasterIter,
CIterComp< int, &CData::m3 > > CSlaveSet3;
//////////////////////////////////////////////////////////

int main()
{
CMasterSet masterSet;
CSlaveSet2 slaveSet2;
CSlaveSet3 slaveSet3;

// populate
for(int c = 0; c < 15; ++c)
{
CData data;
data.m1 = static_cast< double >(rand()) / RAND_MAX * 20;
data.m2 = static_cast< double >(rand()) / RAND_MAX * 20;
data.m3 = static_cast< double >(rand()) / RAND_MAX * 20;
CMasterIter iter = masterSet.insert(data);
slaveSet2.insert(iter);
slaveSet3.insert(iter);
}

// erasing is tricky
{
CData dummy;
dummy.m1 = 10;
CMasterIter iter = masterSet.lower_bound(dummy);
// suppose you have an iterator into the master set
// you want to erase THAT item from all sets
// doing slaveSet2.erase(iter) might not do what you want
// while std::find will use equality comparison
// between iterators
// ah... erase first from slaves or else... UB
////////////////////////////////////////////////////////////////
// More errors:
// error C2065: 'find' : undeclared identifier
// error C2039: 'find' : is not a member of 'std'
////////////////////////////////////////////////////////////////
slaveSet2.erase(
std::find(slaveSet2.lower_bound(iter),
slaveSet2.end(), iter));
slaveSet3.erase(
std::find(slaveSet3.lower_bound(iter),
slaveSet3.end(), iter));
masterSet.erase(iter);
}

// DEFAULT ORDERING
for(CMasterIter iter = masterSet.begin();
iter != masterSet.end(); ++iter)
std::cout << *iter;

std::cout << std::string(20, '-') << std::endl;

// SECOND ORDERING
for(CSlaveSet2::iterator iter = slaveSet2.begin();
iter != slaveSet2.end(); ++iter)
std::cout << **iter;

std::cout << std::string(20, '-') << std::endl;

// THIRD ORDERING
for(CSlaveSet3::iterator iter = slaveSet3.begin();
iter != slaveSet3.end(); ++iter)
std::cout << **iter;

return 0;
}
// END CODE
 
M

Mike Copeland

(e-mail address removed) (Mike Copeland) wrote in



The advice is to abandon VS6 and switch over to a proper C++ compiler.
There are also free versions of VS2010 available as I've heard.

Alternatively, if the compiler does not like some template syntax you
always have the option to manually generate the templated funtion for
each needed specialization. It's easy in this example as there are only 2
specializations (for m2 and m3), see below:
Yes, that compiles and executes. Now I can delve into it and try to
understand the new techniques being used. Thank you very much!
 

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

Similar Threads


Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,045
Latest member
DRCM

Latest Threads

Top