There are simple STL algorithms that can handle the
map< string, vector<string> >
and
map< string, map< string, vector<Struct> > >
easily.
FIRST STRUCTURE
map< string, vector<string> >
You'll first need a functor to find date2:
1 2 3 4 5 6 7
|
struct date_equals
{
bool operator () (string date, const Struct& struc)
{
result = (date == struc.date);
}
};
|
If you want to know how many elements of date1 match date2.
1 2 3 4 5
|
long num_matches = count(
m[ date1 ].second.begin(),
m[ date1 ].second.end(),
bind1st( date_equals(), date2 )
);
|
Copy elements that match date1 and date2 into a new vector.
1 2 3 4 5 6
|
vector<Struct> date1and2data( num_matches );
copy(
m[ date1 ].second.begin(),
m[ date1 ].second.begin() +num_matches,
date1and2data.begin()
);
|
Alas, there's no 'copy_if()' STL algorithm (an oversight), but you can create your own easily. Let's make one that knows how to push_back():
1 2 3 4 5 6 7 8 9 10 11
|
template <class Container, class UnaryPredicate>
void push_back_if(
Container& container,
typename Container::iterator begin,
typename Container::iterator end,
UnaryPredicate pred
) {
for (; begin != end; begin++)
if (pred( *begin ))
container.push_back( *begin );
}
|
Now you can directly copy elements matching date1 and date2 by appending them to a new vector.
1 2 3 4 5 6 7
|
vector<Struct> date1and2data;
push_back_if(
date1and2data,
m[ date1 ].second.begin(),
m[ date1 ].second.end(),
bind1st( date_equals(), date2 )
);
|
If you want to do something to a range of dates, you can use
transform()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
struct print_stuff
{
string date1, date2;
ostream& outs;
explicit print_stuff( string date1, string date2, ostream& outs ): date1(date1), date2(date2), outs(outs) { }
Struct operator () (const Struct& struc)
{
outs << date1 << ", " << date2 << ", " << struc.value1 << ", " << struc.value2 << endl;
return struc; // don't actually change anything
};
};
...
transform(
date1and2data.begin(),
date1and2data.end(),
print_stuff( date1, date2, cout )
);
|
Or you can, again, go directly for it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
struct print_stuff
{
string date1, date2;
ostream& outs;
explicit print_stuff( string date1, string date2, ostream& outs ): date1(date1), date2(date2), outs(outs) { }
Struct operator () (const Struct& struc)
{
if (struc.date == date2)
outs << date1 << ", " << date2 << ", " << struc.value1 << ", " << struc.value2 << endl;
return struc;
}
};
...
transform(
m[ date1 ].second.begin(),
m[ date1 ].second.end(),
print_stuff( date1, date2, cout )
);
|
SECOND STRUCTURE
map< string, map< string, vector<Struct> > >
It isn't necessarily as intimidating as it appears. In fact, in some respects its easier. Now for the same stuff as above.
To count the number of matching dates
|
size_type num_matches = m[ date1 ].second[ date2 ].second.size();
|
Woah! Nice!
Copy matching elements
Oh, wait... You've already got a list of matching elements! :-)
|
m[ date1 ].second[ date2 ].second
|
To do something to a range of elements,
transform() still fits the bill.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
struct print_stuff
{
string date1, date2;
stream& outs;
explicit print_stuff( string date1, string date2, stream& outs ): date1(date1), date2(date2), outs(outs) { }
Struct operator () (const Struct& struc)
{
outs << date1 << ", " << date2 << ", " << struc.value1 << ", " << struc.value2 << endl;
return struc;
}
};
transform(
m[ date1 ].second[ date2 ].second.begin(),
m[ date1 ].second[ date2 ].second.end(),
print_stuff( date1, date2, cout )
);
|
Amazing.
BTW. Hopefully you noticed that the first and third 'print_stuff' functors were exactly the same, and the second differed by only one line. (Of course, the type of 'Struct' was different between the first two and the last.)
Hope this helps.
[edit] Yoinks! I'm living in molasses land....