双地图插入问题

时间:2011-09-07 16:34:02

标签: c++ string stl map operator-overloading

我有一个 stl :: map,其键定义为我定义的对象和int。地图的使用如下: 我有一个特定对象的列表,我想要计算我有多少相同的对象。所以我将对象插入到map中。如果对象已经存在于map中,我会增加它的值(因此是计数器)。该对象定义了所有基本运算符。该对象由5个字符串组成。 ==运算符定义为所有5个字符串的比较,并且在上下文中逻辑上是有意义的。问题是运营商<在上下文中没有逻辑意义。我只关心物体是否平等。我无法定义两个不同对象中的哪一个更大。因为stl map定义了此运算符作为if else梯形图的结果,并且在每个运算符中我将其与“<”进行比较五个中的另一个字符串。如果为true则返回true,如果....并且最后一个返回false。在对象的特定情况下,我有三个相同的实例,我得到的地图包含两个相同的对象作为键,其中一个具有1的计数器,另一个具有2。 我无法理解这是什么问题,怎么可能发生。 对于那些请求一些代码示例的人 - 由于我无法解释的原因 - 我不能发布代码本身,但我会写一个很好的例子(请忽略一些小东西,比如丢失';' - 我在5中写了它分钟):

class Example
{
private:
    string one;
    string two;
    string three;
    string four;
    string five;
public:
    inline Example (string a_one,string a_two, string a_four, string a_five) :
        one(a_one),two(a_two),three(a_three),four(a_four),five(a_five)
        {}

    inline bool operator == (const Example& other) const
    {
        if (one == other.one)
        {
            if (two == other.two)
            {
                if (three == other.three)
                {
                    if (four == other.four)
                    {
                        if (five == other.five)
                        {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    inline bool operator < (const Example& other) const
    {
        if (one < other.one)
        {
            return true;
        }
        else if (two < other.two)
        {
            return true;
        }
        else if (three < other.three)
        {
            return true ;
        }
        else if (four < other.four)
        {
            return true;
        }
        else if (five < other.five)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

void CountExample(Example& example,std::map<Example,int>& counters);

void main()
{
    std::map<Example,int> counters;
    std::list<Example> examples = GetExamples();
    //GetExamples defined elsewhere, and initializes examples with a long list of instances of Example
    std::list<Example>::const_iterator Iter;
    for (Iter = examples.begin();Iter != examples.end();Iter++)
    {
        CountExample(*Iter);
    }
    PrintCounters(counters);//PrintCounters defined elsewhere and prints the map to a file
}

void CountExample(Example& example,std::map<Example,int>& counters)
{
    std::map<Example,int>::const_iterator Iter;
    Iter = counters.find(example);
    if (Iter ==counters.end()) //means the specific Example is not in the map
    {
        counters.insert(std::pair<Example,int>(example,1));
    }
    else
    {
        counters[example] += 1;
    {
}

4 个答案:

答案 0 :(得分:2)

如果你有一个相当现代的编译器,那么这个比较阶梯可以用两个std::tie()'元组之间的单一比较代替:

#include <tuple>
...
bool operator== (const Example& other) const
{
    return std::tie(one, two, three, four, five)
        == std::tie(other.one, other.two, other.three, other.four, other.five);
}
bool operator < (const Example& other) const
{
    return std::tie(one, two, three, four, five)
         < std::tie(other.one, other.two, other.three, other.four, other.five);
}

顺便说一句,使用std::multiset计算特定元素存储在关联容器中的次数可能更简单,这可以将CountExample简化为单行

void CountExample(const Example& example, std::multiset<Example>& counters)
{
    counters.insert(example);
}

虽然打印变得有点棘手:

void PrintCounters(const std::multiset<Example>& counters)
{
    for(auto i=counters.begin(); i!=counters.end(); i = counters.upper_bound(*i))
            std::cout << *i << ":" << counters.count(*i) << '\n';
}

对ideone进行测试:http://ideone.com/uA7ao

答案 1 :(得分:1)

要与多个元素进行比较,您比较的每个元素都将具有三个结果:小于,大于或等效。您必须考虑所有这些情况。

bool LessThan(const MyClass & left, const MyClass right)
{
    if (left.one < right.one)
        return true;
    else if (right.one < left.one)
        return false;
    // equivalent in one
    if (left.two < right.two)
        return true;
    else if (right.two < left.two)
        return false;
    // equivalent in one and two
        ...
    return false;
}

答案 2 :(得分:0)

编辑:在考虑了这个问题之后,我决定删除我的旧答案,因为它似乎与当前遇到的问题无关。您的operator<方法似乎确实满足严格弱排序的要求,因此我认为问题出在其他地方,所以我将在下面留下以下备用解决方案......

您似乎在为地图创建总订单时遇到问题,因此您可能希望将std::unordered_map作为替代方案,直接应用operator==来检测相等性,而不是使用你的operator<用于严格的弱排序......你必须为你的类提供一个哈希函数,否则使用基于哈希表的std::unordered_map容器非常简单。

答案 3 :(得分:0)

您需要为您输入operator<。编写这可能非常繁琐,但您只需使用Boost.Tuple即可 - 这样,元组处理比较,使代码更易于阅读,编写和理解。

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <string>

struct Object
{
    std::string a;
    std::string b;
    std::string c;
};

bool operator<(const Object& obj1, const Object& obj2)
{
    return (boost::tie(obj1.a, obj1.b, obj1.c) < 
        boost::tie(obj2.a, obj2.b, obj2.c));
}