使用STL Map查找对中第一个元素的最低密钥对

时间:2013-09-21 19:17:26

标签: c++ map iterator key std-pair

我有一张地图,其键是一对std::map<std::pair<int, int>, struct A> myMap。如何找到并访问对中每个唯一第一个元素的最低对?例如,

struct A a;
myMap.insert(std::make_pair(std::pair<int, int>(1, 200), a));
myMap.insert(std::make_pair(std::pair<int, int>(1, 202), a));
myMap.insert(std::make_pair(std::pair<int, int>(2, 198), a));
myMap.insert(std::make_pair(std::pair<int, int>(2, 207), a));

我想要使用的密钥是&lt; 1,200&gt;和&lt; 2,198&gt;。我不需要他们一起返回,我只需要对每个人进行操作。

谢谢你的时间!

4 个答案:

答案 0 :(得分:0)

我会选择最直接的解决方案:

auto previous_first = 0;
auto is_first_iteration = true;
for (const auto& key_value : myMap) {
  const auto& key = key_value.first;
  const auto& value = key_value.second;
  if (is_first_iteration || key.first != previous_first) {
    is_first_iteration = false;
    previous_first = key.first;
    // do something here!
  }
}

这里你只是简单地迭代每个元素(我们依赖于std :: map的属性,元素被排序。对,它们由第一个元素排序,然后由第二个元素排序)。在每一步中我们都会记住前面的第一个元素 - 如果在这一步中我们只是跳过这一步。

@AndrewDurward指出这个问题可以在对数时间内解决。这只是部分原因。首先,这个问题只能在最好的情况下以对数时间来解决。如果你有N个元素并且每个元素都有不同的first怎么办?答案中有N个元素,显然,你不能以对数时间输出N个元素。

答案 1 :(得分:0)

您可以使用自定义比较器

struct comp {
bool operator()(const std::pair<int, int>&x, const std::pair<int, int>& y ) const
{
    return x.second < y.second;
}
};

std::map<std::pair<int, int>, struct A,comp > myMap;

然后找到然后使用find_if和第一个元素。

在您的情况下,std::less<T>默认按预期排序。

所以下面的工作没有自定义比较器,只有

std::map<std::pair<int, int>, struct A > myMap;

int search_id=1; //First Element of pair, you can use entire pair too, 
//but that will defeat the purpose of "lowest pair"
auto it=std::find_if(myMap.begin() , myMap.end() , 
                [search_id](const std::pair<std::pair<int, int>, A>& x)
                { return x.first.first == search_id; } 
                );

if(it != myMap.end())
{
std::cout<<it->first.first<<" "<<it->first.second;
}

编辑:您可以将其用作循环所有元素的函数

答案 2 :(得分:0)

使用微小的超载助手,您只需使用std::lower_bound Live on Coliru

列出的第一个匹配项是您查找的匹配项(std::pair<>已经按(first,right)排序,升序)。

在这种情况下,助手是:

struct ByKeyFirst final { int value; };
inline bool operator<(Map::value_type const& v, ByKeyFirst target) { 
    return v.first.first < target.value; 
}

正如您所看到的,唯一的“增加的复杂性”是检查发现匹配,但效率应该没问题。而且你总是可以隐藏(单元可测试的)助手的复杂性:

Map::const_iterator byKeyFirst(Map const& map, int target)
{
    auto const e = end(map);
    auto lbound = lower_bound(begin(map), e, ByKeyFirst { target });
    if (lbound != e && lbound->first.first == target)
        return lbound;
    return e;
}

现在查找代码变为:

int main()
{
    const Map myMap { 
        { { 1, 200 }, {} },
        { { 1, 202 }, {} },
        { { 2, 198 }, {} },
        { { 2, 207 }, {} },
    };

    auto match = byKeyFirst(myMap, 2);

    if (end(myMap) != match)
        std::cout << "Matching key: (" << match->first.first << "," << match->first.second << ")\n";
}

完整演示

#include <map>
#include <tuple>
#include <limits>

using namespace std;

struct A {};

using Pair = pair<int,int>;
using Map  = map<Pair, A>;

namespace /*anon*/
{
    struct ByKeyFirst final { int value; };
    inline bool operator<(Map::value_type const& v, ByKeyFirst target) { return v.first.first < target.value; }

    Map::const_iterator byKeyFirst(Map const& map, int target)
    {
        // you can just find the first match, Pair is already sorted by `first`, then `second`:
        auto const e = end(map);
        auto lbound = lower_bound(begin(map), e, ByKeyFirst { target });
        if (lbound != e && lbound->first.first == target)
            return lbound;
        return e;
    }
}

#include <iostream>

int main()
{
    const Map myMap { 
        { { 1, 200 }, {} },
        { { 1, 202 }, {} },
        { { 2, 198 }, {} },
        { { 2, 207 }, {} },
    };

    auto match = byKeyFirst(myMap, 2);

    if (end(myMap) != match)
        std::cout << "Matching key: (" << match->first.first << "," << match->first.second << ")\n";
}

答案 3 :(得分:0)

由于地图键按字典顺序排序,因此它们也可以被视为按其第一个元素排序(尽管有一些重复)。这意味着只要我们提供适当的谓词,我们就可以利用对排序范围进行操作的任何标准算法。在这种情况下,比较键的第一个元素的谓词可以写成如下:

    typedef std::map<std::pair<int, int>, struct A> myMap_t;

    auto compare_first = [](
        myMap_t::value_type const & p1,
        myMap_t::value_type const & p2 )
    {
        return p1.first.first < p2.first.first;
    };

完成后,我们只需要选择正确的算法来迭代所需的地图元素。我们想要地图中的第一个元素,然后是第一个与谓词定义的元素“不等同”的元素。这正是std::upper_bound所做的。

auto e1 = myMap.begin();
auto e2 = std::upper_bound( e1, myMap.end(), *e1, compare_first );

或者我们可以循环使用它们:

for( auto it = myMap.begin(); it != myMap.end(); it = std::upper_bound( it, myMap.end(), *it, compare_first ) )
        std::cout << it->first.first << " " << it->first.second << "\n";

完整代码为here