Hi,
I'm trying to use the STL map class to be able to store keys and associated values. I started out using it with keys of pre-existing data types like int, string, etc. and was working fine. I was also able to use it with values of custom classes.

I'm now trying to use it to store keys of custom classes. To do so, it appears to require the creation of the < operator (presumably so that the map can sort the keys).

My question is this - what is the proper code inside the < operator? Below is what I have, (and it compiles and seems to work), but I'm not sure it makes sense. How would it need to change if I had other data types inside my KeyObj class as well? Also, should I somehow account for the fact that if lastName is blank on one object and firstName is blank on the other object being compared, that they might be considered equal? - would I handle that by putting a separator in between when comparing?)

class KeyObj
{
public:
string lastName;
string firstName;
bool operator< (const KeyObj &compare)
{
return lastName+firstName < compare.lastName+compare.firstName;
}
};
bool operator< (const KeyObj &source, const KeyObj &compare)
{
return source.lastName+source.firstName < compare.lastName+compare.firstName;
}
int main( int argc, char * argv[] )
{
map<KeyObj,string> myMap;
KeyObj k;
k.lastName="JONES";
k.firstName="BOB";
myMap[k] = "MR. BOB JONES";
KeyObj k2;
k2.lastName="JONES";
k2.firstName="FRED";
myMap[k2] = "MR. FRED JONES";
cout<<"Searching for FRED JONES:"<<endl;
KeyObj test;
test.lastName="JONES";
test.firstName="FRED";
if ( myMap.find(test) != myMap.end() )
{
cout<<myMap[test]<<endl;
}
else
cout<<"COULDN't FIND IT"<<endl;

------------------------

Searching for FRED JONES:
MR. FRED JONES

Code tags don't help much if your code isn't formatted to begin with.

>what is the proper code inside the < operator?
That depends on the needs of the class. Does it make more sense to compare by first name, last name, or both? How you define operator< depends heavily on that decision. However, once it's made, the implementation is somewhat trivial in your case:

#include <iostream>
#include <string>
#include <map>

class Person {
  std::string _first, _last;
public:
  Person(const std::string& first, const std::string& last)
    : _first(first), _last(last)
  {}

  bool operator<(const Person& p) const
  {
    //return _last < p._last;
    //return _first < p._first;
    return _last + _first < p._last + p._first;
  }

  friend std::ostream& operator<<(std::ostream& out, const Person& p)
  {
    return out<< p._last <<", "<< p._first;
  }
};

int main()
{
  std::map<Person, int> m;

  ++m[Person("John", "Doe")];
  ++m[Person("Jane", "Doe")];
  ++m[Person("", "Doe")];
  ++m[Person("John", "Doe")];
  ++m[Person("John", "")];

  std::map<Person, int>::iterator it = m.begin();

  while (it != m.end()) {
    std::cout<< it->first <<" -- "<< it->second <<std::endl;
    ++it;
  }
}

Narue,

Assuming I want to compare by both last and first (I created this as a trivial example - I have many more fields, all of which are important) - do I need to deal with an 'empty' last or an 'empty' first which might make two items equal? (or even better a last name of "AB" with a first name of "CD" vs. a last name of "A" and a first name of "BCD"..

(ie would lastname + "-" + firstname < other.lastname + "-" + other.firstname )

make it 'safer'?

Also, in the syntax you are using for inserting into the map(which I've never seen before), what int is being assigned for the value?

Also, in the syntax you are using for inserting into the map(which I've never seen before), what int is being assigned for the value?

Beautiful isn't it?

>do I need to deal with an 'empty' last or an 'empty' first which might make two items equal?
The only situation where this would be true is if the last name is the same and the first name is empty for both objects (or vice versa). Of course, they would be equal and it's hard to figure out a way to avoid that since you would basically be saying "Strings that are equal are equal, except...", which is nonsensical.

>or even better a last name of "AB" with a first name of "CD" vs. a last name of "A" and a first name of "BCD".
Now that makes more sense, and you're on the right track for how to solve it.

>what int is being assigned for the value?
If not value is given, it defaults to T(), which is 0 for int. So for each name added, I'm incrementing the value starting with 0.

Narue,

You mentioned in one of the earlier posts that it depends on how I want to compare whether I compare both last name and first name or just last name, etc. If a map is unique/sorted, wouldn't I be required to include every class field in the < operator?

>If a map is unique/sorted, wouldn't I be required to include every class field in the < operator?
Only if you want every member to be a part of the key. It depends on the class what it means for one object to be less than another.

This article has been dead for over six months. Start a new discussion instead.