简体   繁体   English

如何以特定方式在c ++ STL中查找?

[英]How to find in c++ STL in a specific manner?

map< pair<int,int> , int > m ;

Here pair.first and pair.second are positive and pair.second >= pair.first . 这里pair.firstpair.second是正数, pair.second >= pair.first

I would like to find all iterator/s in map m such that for a given key. 我想找到映射m所有迭代器,以便针对给定的键。 Key is an integer which lies between pairs eg key is 2 and pair is [2,5] and [1,2] etc. Key是位于对之间的整数,例如key为2,对为[2,5][1,2]等。
eg m[1,3] = 10 , m[3,5] = 6 , m[1,8] = 9 , m[7,8] = 15 then when I search for m.find(3) then it would return iterator for m[1,3] , m[1,8] , m[3,5] .If there is no key then it would return m.end() . 例如m[1,3] = 10 , m[3,5] = 6 , m[1,8] = 9 , m[7,8] = 15则当我搜索m.find(3)时返回m[1,3]m[1,8]m[3,5]迭代器。如果没有键,则返回m.end()

I'm not sure why you want to do this, but these days Boost Interval Container library is pretty capable. 我不确定为什么要这样做,但是现在Boost Boost Interval Container库已经足够了。

Assuming that you might have wanted to keep track of the total (sum) of mapped values for a specific point, you could simply apply a splitting Combining Style to your input data and profit: 假设你也许是想跟踪映射值的 (总和)为一个特定的点,你可以简单地套用一个分裂风格结合到你的输入数据和利润:

Live On Coliru 生活在Coliru

#include <boost/icl/split_interval_map.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>

namespace icl = boost::icl;

int main() {
    using Map  = icl::split_interval_map<int, int>;
    using Ival = Map::interval_type;
    Map m;
    m.add({Ival::closed(1,3), 10});
    m.add({Ival::closed(3,5), 6});
    m.add({Ival::closed(1,8), 9});
    m.add({Ival::closed(7,8), 15});

    for (auto e : m) std::cout << e.first << " -> " << e.second << "\n";

    std::cout << "------------------------------\n";

    for (auto e : boost::make_iterator_range(m.equal_range(Ival::closed(3,3))))
        std::cout << e.first << " -> " << e.second << "\n";
}

This will tell us: 这将告诉我们:

[1,3) -> 19
[3,3] -> 25
(3,5] -> 15
(5,7) -> 9
[7,8] -> 24
------------------------------
[3,3] -> 25

Notice how 注意如何

  • the consolidation very accurately reflects that the point [3,3] is the only only point that coincided with both [1,3] and [3,5] from the input data simultaneously, and as a result, we get halfopen intervals in the combined set ( [1,3) , [3,3] and (3,5] ). 合并非常准确地反映出, [3,3]是唯一同时与输入数据中的[1,3][3,5]一致的点,因此,我们在组合集( [1,3)[3,3](3,5] )。
  • Note also how the query for this one point correctly returns the sum of 10+6+9 for all the three intervals you were interested in. 另请注意,针对这一点的查询如何针对您感兴趣的所有三个时间间隔正确返回10+6+9的总和。

What Use Is This? 这有什么用?

So, you see I shifted the focus of the question from the "How?" 因此,您看到我将问题的焦点从“如何?”转移了。 to the "What?". 到“什么?”。 It usually helps to state the goal of code instead of the particular mechanics. 通常,它有助于陈述代码的目标,而不是特定的机制。

Of course, if instead of the sum you'd have been interested in the average, the minimum or the maximum, you'd likely find yourself writing some custom combining strategy. 当然,如果您对平均值,最小值或最大值而不是总和感兴趣,那么您可能会发现自己正在编写一些自定义合并策略。

Bonus In case you wanted, here's how you can at least write the solution to the problem posed in the OP using Boost Icl: Live On Coliru . 奖励如果您愿意,这里至少可以使用Boost Icl: Live On Coliru来写出解决OP中出现的问题的解决方案。 Though it's not particularly efficient, it's straight forward and robust. 尽管它不是特别有效,但它简单而强大。

There's no way to avoid a linear search from the start of the map, because if the first element is {0,INT_MAX} then it matches and the elements you want are not necessarily in a contiguous range, eg if you have {1,3},{2,2}{3,5} you only want the first and last elements when the key is 3. 无法避免从地图开始进行线性搜索,因为如果第一个元素为{0,INT_MAX},则它匹配并且您想要的元素不一定在连续范围内,例如,如果您有{1,3 },{2,2} {3,5}仅在键为3时才需要第一个和最后一个元素。

You can stop searching when you reach an element with first greater than the key. 当您到达first大于键的元素时,可以停止搜索。

Something like this (untested): 像这样(未经测试):

typedef map< pair<int,int> , int > Map;

std::vector<Map::iterator>
find(int key, const Map& m)
{
  std::vector<Map::iterator> matches;
  for (Map::iterator it = m.begin(), end = m.end(); it != end && key <= it->first; ++it)
  {
    if (it.first >= key && key <= it.second)
      matches.push_back(it);
  }
  return matches;
}

You could turn it into a functor and use find_if but I'm not sure it's worth it. 您可以将其转换为函子并使用find_if但我不确定是否值得。

If you just want one iterator returned per call: 如果只希望每个调用返回一个迭代器:

typedef map< pair<int,int> , int > Map;

Map::iterator
find(int key, const Map& m, Map::iterator it)
{
  for (Map::iterator end = m.end(); it != end && key <= it->first; ++it)
  {
    if (it.first >= key && key <= it.second)
      return it;
  }
  return m.end();
}

Map::iterator
find(int key, const Map& m)
{ return find(key, m, m.begin()); }

I think that instead of iterators you could store (and use) corresponding keys of the map. 我认为可以代替(迭代器)存储(并使用)地图的相应键。 If so then the code could look like 如果是这样,那么代码可能看起来像

#include <iostream>
#include <map>
#include <algorithm>
#include <vector>
#include <utility>

int main() 
{
    std::map<std::pair<int, int>, int> m;
    m[{ 1, 3}] = 10; 
    m[{ 3, 5}] = 6;
    m[{ 7, 8}] = 15;

    typedef std::map<std::pair<int, int>, int>::value_type value_type;
    typedef std::map<std::pair<int, int>, int>::key_type key_type;

    int search;

    auto in_range = [&search]( const value_type &value )
    {
        return value.first.first <= search && search <= value.first.second; 
    };

    search = 3;

    std::vector<key_type> v;
    v.reserve( std::count_if( m.begin(), m.end(), in_range ) );

    for ( const auto &p : m )
    {
        if ( in_range( p ) ) v.push_back( p.first );
    }

    for ( const auto &p : v ) 
    {
        std::cout << "[ " << p.first << ", " << p.second << " ]" << std::endl;
    }

    return 0;
}

The output is 输出是

[ 1, 3 ]
[ 3, 5 ]

Take into account that it is supposed that key.first is less than or equal to key.second where key is the key of the map. 考虑到key.first小于或等于key.second,其中key是映射的键。

if you only need an iterator to the next value found in the map, you can use the std::find_if algorithm like this: 如果您只需要迭代器即可访问映射中找到的下一个值,则可以使用std :: find_if算法,如下所示:

int key=2;
map<pair<int,int>, int>::iterator it =std::find_if(m.begin(),m.end(),
                         [key](pair<pair<int,int>,int> entry)
                         {
                           return (entry.first.first <= key) 
                                  && (entry.first.second >= key);
                         }
                         );

cout << "the next value is: [" << it->first.first << "/";
cout << it->first.second << "] " << it->second << endl;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM