双地图插入问题

发布于 2024-12-03 13:10:18 字数 2832 浏览 1 评论 0原文

我有一个 stl::map 的键定义为我定义的对象,以及 int。地图的使用如下: 我有一个特定对象的列表,我想计算我有多少个相同的对象。因此,我将对象插入到地图中。如果该对象已存在于地图中,我会增加它的值(因此计数器)。该对象定义了所有基本运算符。该对象由 5 个字符串组成。 == 运算符定义为所有 5 个字符串的比较,在上下文中逻辑上是有意义的。问题是运算符 <在上下文中没有逻辑意义。我只关心对象是否相等。我无法定义两个不同对象中哪一个更大。因此,为了 stl map 的缘故,将此运算符定义为 if elseladder 的结果,并且在每个 if 中我与“<”进行比较五个中的另一串。如果 true 返回 true else,if.... 最后的 else 返回 false。在 object 的特定情况下,我有三个相同的实例,我得到了包含两个相同对象作为键的映射,其中一个的计数器为 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;
    {
}

I have an
stl::map that has the key defined as an object I defined, and int. The use of the map is as follows:
I have a list of the specific object and I want to count how many identical objects I have. So I insert the objects into the map.if the object already exists in the map I increase it's value (hence the counter). The object has all the basic operators defined. The object consist of 5 strings. The == operator defined as the comparison of all 5 strings, and logically is meaningfull in the context. The problem is that the operator < has no logic meaning in the context. I care only if the objects are equal. I can't define which of two different objects is bigger.so for the sake of stl map defined this operator as the result of if else ladder and in each if I compared with "<" another string of the five. If true return true else, if.... And the last else returns false. In a specific case of the object , where I had three identical instances, I got the map containing two identical objects as keys, one of them had the counter of 1 and the other had 2.
i can't understand what is the problem and how could it happen.
For those who requested some code examples - for reason i can't explain - i can't post the code itself, but i will write a good example of it(please ignore little things like missing ';' - i wrote it in 5 minutes):

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;
    {
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

青巷忧颜 2024-12-10 13:10:18

如果您有一个相当现代的编译器,则可以用两个 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

If you have a reasonably modern compiler, that ladder of comparisons can be replaced with a single comparison between two std::tie()'d tuples:

#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);
}

Incidentally, it may be simpler to use a std::multiset to count the number of times a particular element is stored in an associative container, that simplifies CountExample to a one-liner

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

Although printing becomes a bit more tricky:

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';
}

Test on ideone: http://ideone.com/uA7ao

泪冰清 2024-12-10 13:10:18

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

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;
}

To make a comparison with multiple elements, each element that you compare will have three outcomes: less than, greater than, or equivalent. You must account for all of these cases.

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;
}
只怪假的太真实 2024-12-10 13:10:18

您需要为您的键入提供一个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));
}

You need to provide an operator< for you type. This can be pretty tedious to write, but you can simply it by using a Boost.Tuple - that way, the tuple handles the comparisons, leaving your code easier to read, write and understand.

#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));
}
甜味超标? 2024-12-10 13:10:18

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

看来您在为地图创建总顺序时遇到问题,因此您可能需要查看 std::unordered_map 作为直接应用您的 operator== 用于检测相等性,而不是使用您的operator< 用于严格的弱排序...您必须为您的类提供哈希函数,否则使用基于哈希表的 std::unordered_map 容器非常简单。

Edit: After thinking about the problem some more, I've decided to removed my older answer since it did not seem pertinent to the current problem being experienced. Your operator< method does seem to be fulfilling the requirements for a strict weak ordering, so I think the problem lies somewhere else, and so I'm leaving the following alternate solution below ...

It seem you're having issues creating a total order for your map, so you might want to look at std::unordered_map as an alternative that will directly apply your operator== for detecting equality, rather than using your operator< for a strict weak ordering ... you'll have to provide a hash-function for your class, but otherwise the use of the hash-table based std::unordered_map container is pretty straight-forward.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文