如何比较 std::map 中的所有项目?

How to compare all items in std::map?

我想比较 std::map 中的所有值。

我坚持:对于线性容器,如矢量,我会循环索引 i=1; v[i].isUniform(v[i-1])。但我不能用地图做到这一点。我期待听到聪明的想法。

这是我想要完成的一些伪代码:

class MyData
{
public:
    bool isUniform(const MyData& other) const
    {
        return this->speed == other.speed && this->ban == other.ban;
    }

private:
    bool ban;
    int  speed;
}

std::map<int, MyData> myMap;

bool allUniform = true;
for(item_1, item_2 : myMap) // how to implement this?
{
    if(!item_1.isUniform(item_2))
    {
        allUniform = false;
    }
}

最优雅(可读且高效)的方法是什么?

for(item_1, item_2 : myMap) // how to implement this?

但是如果它们都彼此相等(假设 isUniform 是可传递的并且是对称的),那就等同于说它们都等于第一个元素。因此,您可以将每个元素与第一个元素进行比较。

天真地,我们得到:

bool allUniform(std::map<int, MyData> const &m)
{
    if (m.empty()) return true; // or whatever makes sense for you

    auto first = m.begin();
    for (auto current = m.begin(); ++current != m.end(); )
    {
        if (!first->second.isUniform(current->second))
        {
            return false;
        }
    }
    return true;
}

如果您不介意将第一个元素与其自身进行比较,则可以对此进行简化,因为实际上大部分复杂性只是为了避免这种情况。

使用下面的 std::adjacent_find 或其他答案中的 std::all_of 解决方案可能会更好。

bool allUniform(std::map<int, MyData> const &m)
{
    auto first_non_uniform =
        std::adjacent_find(
            m.begin(), m.end(),
            [](auto left, auto right)
            {
                return !(left->second.isUniform(right->second));
            }
           );

    return first_non_uniform == m.end();
}

您可以将 std::all_of 与 lambda 一起使用。那看起来像

bool allUniform = std::all_of(std::next(myMap.begin()), 
                              myMap.end(), 
                              [&myMap](const auto& pair)
                              { return myMap.begin()->second.isUniform(pair.second); });

这来自 [1, N) 并针对第一个元素再次调用 isUniformall_of 也有短路,所以一旦结果不一致,它就会结束。

将集合中的所有元素与第一个元素进行比较:

template<class M, class F>
bool allEqual( M const& m, F&& f ) {
  using std::begin; using std::end;
  auto b = begin(m);
  auto e = end(m);
  if (b == e) return true;
  for (auto it = std::next(b); it != e; ++it)
    if (!f( *b, *it))
      return false;
  return true;
}

成对比较所有元素:

template<class M, class F>
bool pairwiseCompare( M const& m, F&& f ) {
  for (auto&& a:m)
    for (auto&& b:m)
    {
      if (std::addressof(a) == std::addressof(b))
        continue;
      if (!f(a,b))
        return false;
    }
  return true;
}

这不适用于 std::vector<bool> 这样的伪容器;好吧,它有点会,但它会浪费自己比较元素。

isUniform() 是可传递的吗?也就是说,它是否对任何 3 个 MyData 对象都遵循此规则:

 isUniform(A, B) && isUniform(B, C) == isUniform(A, C)

如果是这样,那么你只需要 O(n) 次比较。这是我的测试代码:

#include <iostream>
#include <map>

using namespace std;

class MyData {
public:
    int value;
    MyData(int _value) : value(_value) {}

    bool isUniform(const MyData &obj) const { return value == obj.value; }

    static void checkMap(map<int, MyData> myMap) {
         bool allUniform = true;
         MyData * firstItem = nullptr;

         for (auto it = myMap.begin(); allUniform && it != myMap.end(); ++it) {
             if (firstItem == nullptr) {
                  firstItem = &it->second;
             }
             else {
                  allUniform = firstItem->isUniform(it->second);
             }
         }

         cout << "All Uniform: " << (allUniform ? "Yes" : "No") << endl;
    }
};

int main(int, char **) {
    map<int, MyData> map1;
    map<int, MyData> map2;
    MyData a1(1);
    MyData b1(1);
    MyData b2(2);
    MyData c1(1);

    // Should be uniform
    map1.insert(std::pair<int, MyData>(1, a1));
    map1.insert(std::pair<int, MyData>(2, b1));
    map1.insert(std::pair<int, MyData>(3, c1));
    MyData::checkMap(map1);

    // Should not be uniform
    map2.insert(std::pair<int, MyData>(1, a1));
    map2.insert(std::pair<int, MyData>(2, b2));
    map2.insert(std::pair<int, MyData>(3, c1));
    MyData::checkMap(map2);

    return 0;
}

有了这个输出:

$ g++ -std=c++0x Foo.cpp -o Foo && Foo
All Uniform: Yes
All Uniform: No

您可以使用标准算法 std::adjacent_find

例如

#include <iostream>
#include <iomanip>
#include <map>
#include <iterator>
#include<algorithm>

class MyData
{
public:
    MyData( bool ban, int speed ) : ban( ban ), speed( speed )
    {
    }

    bool isUniform(const MyData& other) const
    {
        return this->speed == other.speed && this->ban == other.ban;
    }

private:
    bool ban;
    int  speed;
};



int main() 
{
    std::map<int, MyData> myMap =
    {
        { 1, { true, 100 } }, { 2, { true, 100 } }, { 3, { true, 100 } }    
    };

    auto it = std::adjacent_find( std::begin( myMap ), std::end( myMap ),
                                  []( const auto &p1, const auto &p2 ) 
                                  {
                                    return not p1.second.isUniform( p2.second );
                                  } );

    bool allUniform = it == std::end( myMap );

    std::cout << std::boolalpha << allUniform << '\n';

    return 0;
}

程序输出为

true