In article < .com>,
says...
> Hello people!
>
> (This post is best viewed using a monospace font).
>
> I need to create a class, which holds 4 elements:
> std::string ItemName
> int Calories
> int Weight
> int Density
>
> I need to be able to create about 70 instances of this class, each with
> different properties, then I need to sort them three times:
> First, by calories. Then do some stuff.
> Then by Weight. Then do more stuff.
> And finally by Density. After which, I do more stuff.
Just to clarify, I'm going to explicitly state a couple of
assumptions. First of all, it sounds like the data are basically
static -- i.e. you create all of them, and then after that you won't
add or delete any data; you just need to shuffle the existing data
into different arrangements.
Second, it sounds like you only need to work with one arrangement at
a time -- once you start working with the data in a different order,
you're done working with it in the previous order.
Assuming those are both correct, then a map is probably not your best
choice. You're almost certainly better off using an std::vector, and
then using std::sort to sort the data as needed.
To do that, you generally need to create some predicates (usually as
functors) to do the comparisons correctly:
struct Item {
std::string name;
int calories;
int weight;
int density;
};
struct by_calories {
bool operator<(Item const &a, Item const &b) {
return a.calories < b.calories;
}
};
struct by_weight {
bool operator<(Item const &a, Item const &b) {
return a.weight < b.weight;
}
};
Then you specify the appropriate comparison when you do your sort:
std:vector<Item> items;
// Insert data into vector of items here.
std::sort(items.begin(), items.end(), by_calories());
// simulate processing by printing out:
std::copy(items.begin(), items.end(),
std:

stream_iterator<Item>(std::cout, "\n"));
// Now a different order:
std::sort(items.begin(), items.end(), by_weight());
// print out again.
std::copy(items.begin(), items.end(),
std:

stream_iterator<Item>(std::cout, "\n"));
Of course, for those 'copy' calls to work, you'd need to define an
operator<< for Item, so the ostream_iterator knows how to write each
item out. That'd typically be pretty simple, just writing out the
data in order, probably with tabs between them.
Now, let's consider what happens if those assumptions are wrong. If
your data is really dynamic, then you probably _do_ want to use
std::map or std::set after all. Since you apparently want to iterate
in a particular order, but don't need to do lookups based on a single
'key' part, you probably want a set instead of a map. In this case,
you'd (again) use comparison predicates like above, but you'd specify
the correct predicate as part of the type of the set:
std::set<Item, by_calories> items_c;
std::set<Item, by_weight> items_w;
Then you'd start by putting the data into items_c, then when you're
done working with it in order by calories, you copy the data to
items_w, so it'll be sorted by weight. After you're done with that
order, you copy it to a set ordered by density, and so on. In each
case, since it's in a set you can efficiently add and/or remove items
on the fly.
If the second assumption is incorrect, and you really want to be able
to access the data in any order at any time efficiently, you need to
maintain all the orders simultaneously. In this case, you'll probably
want to store the data in one place, and then create three separate
indices by which to access the data. In this case, you get a hybrid:
typically a vector to hold the data itself, and either vectors or
sets of pointers to the data (depending on whether you need to
add/delete data on the fly).
--
Later,
Jerry.
The universe is a figment of its own imagination.