tags:

views:

87

answers:

2

Hi,

I have created a map with ClassExpression as the key and std::string as the value. The key comparator is given below

class ClassExpressionComparator {
public:
    bool operator()(const ClassExpression& lhs,
    const ClassExpression& rhs) const {
           return ((lhs.quantifier == rhs.quantifier) &&
                   (lhs.property.compare(rhs.property) == 0) &&
                   (lhs.concept.compare(rhs.concept) == 0));
    }
 };

ClassExpression contains the 3 fields mentioned in the comparator. I compare all the 3 fields. When I use find() of map, even if the key is not present in the map, it says that it found the key and gives an existing key as the result (getting first key as the result).

I tried the following

boost::shared_ptr< std::map<ClassExpression, std::string, 
ClassExpressionComparator> > cemap(
                new std::map<ClassExpression, 
                std::string, ClassExpressionComparator>());
ClassExpression ce1;
ce1.quantifier = com::xxxx::kb::SOME;
ce1.property = "<http://www.w3.org/2002/07/acts-on&gt;";
ce1.concept = "<http://www.w3.org/2002/07/Tissue&gt;";
populateMap(cemap, ce1);

ClassExpression ce2;
ce2.quantifier = com::xxxx::kb::SOME;
ce2.property = "<http://www.w3.org/2002/07/contained-in&gt;";
ce2.concept = "<http://www.w3.org/2002/07/HeartValve&gt;";
populateMap(cemap, ce2);

ClassExpression ce3;
ce3.quantifier = com::xxxx::kb::SOME;
ce3.property = "<http://www.w3.org/2002/07/has-location&gt;";
ce3.concept = "<http://www.w3.org/2002/07/Endocardium&gt;";

std::map<ClassExpression, std::string, ClassExpressionComparator>::iterator
                       ceIterator = cemap->find(ce3);
if (ceIterator == cemap->end()) {
         std::cout << "Not found" << std::endl;
}
else {
     std::cout << "Found; concept = " << ceIterator->second << std::endl;
}
ClassExpressionComparator cmp;
std::cout << "compare: " << cmp(ce1, ce3) << std::endl; 

populateMap() just does an insert, in my actual code, I do a few more things in it, I wanted to keep the same flow, so left it that way. The output of cmp(ce1, ce3) is 0 but when I do a find(ce3), the result is that it found it at the first key position instead of returning end(). Where am I going wrong here?

Thank you.

Raghava.

+7  A: 

You wrote an equality comparison. map requires a less-than comparison. (Or greater-than if you want the keys in decreasing order.)

My usual idiom for doing this:

bool operator()(const ClassExpression& lhs,
const ClassExpression& rhs) const {
       return lhs.quantifier < rhs.quantifier? true
            : rhs.quantifier < lhs.quantifier? false
            : lhs.property.compare(rhs.property) < 0? true
            : lhs.property.compare(rhs.property) > 0? false
            : lhs.concept.compare(rhs.concept) < 0;
}
Potatoswatter
Raghava
@Raghava: If and only if `a == b`, then `a < b` and `a > b` are both false. And `a > b` is the same as `b < a`. `find` performs both `a < b` and `b < a` at every step. Thinking another way, there are three possibilities: `==`, `<`, and `>`. To eliminate two using Boolean functions, you will need two function calls. So the most efficient, simplest way is to call the same function twice with reversed operands. (Of course, the compiler might optimize both down to one comparison instruction.)
Potatoswatter
FuleSnabel
FuleSnabel
Raghava
@Raghava: It's logarithmic with the size of the map. `find` is a recursive tree descent. The height of a balanced tree is logarithmic with the number of nodes.
Potatoswatter
@Fule: If you want to insert equivalent objects, use `multimap`.
Potatoswatter
@Potatoswatter: Thank you for the explanation :)
Raghava
+2  A: 

The map is a sorted container, the comparator operator it's looking for is one that implements a strict weak ordering, like <. You're giving it an equals operator, which will screw up the ordering.

bshields
Thank you for the reply. Please see my comment on Potatoswatter's post.
Raghava