使用 `std::equal_range` 和 `boost::transform_iterator`

Posted

技术标签:

【中文标题】使用 `std::equal_range` 和 `boost::transform_iterator`【英文标题】:Using `std::equal_range` with `boost::transform_iterator` 【发布时间】:2020-08-01 16:43:28 【问题描述】:

假设我有一个 Items 的结构,我将其存储在 std::set 中并按如下方式排序:

struct Position

    int x;
    int y;


struct Item

    std::string id;
    Position position;

    // NOTE: only `position` should matter for equality
    operator==(const Item& other)
    
        return position == position;
    
;

inline bool operator<(const Item& lhs, const Item& rhs)

    if (lhs.position.x == rhs.position.x)
    
        return lhs.position.y < rhs.position.y;
    

    return lhs.position.x < rhs.position.x;


using ItemSet = std::set<Item>;

我想使用std::equal_range 搜索ItemSet,但我想使用Position 进行搜索。我知道我可以这样做:

ItemSet items;

Item tempItem;
tempItem.position = some_position;
auto result = std::equal_range(items.begin(), items.end(), tempItem);

但我想避免使用临时的Item

我尝试像这样使用boost::transform_terator

  auto tr = [](const Item& item)  return item.pos; ;
  auto tr_begin = boost::make_transform_iterator(items.begin(), tr);
  auto tr_end = boost::make_transform_iterator(items.end(), tr);
  
  Position findme  2, 1 ;
  auto result = std::equal_range(tr_begin, tr_end, findme);

但是由于我不理解的原因,这不能编译,而且即使它确实有效,我如何从result 获取原始集合的迭代器?或者也许有更好的方法来做到这一点?

这是一个显示问题的测试工具:http://cpp.sh/3hzsq

任何帮助将不胜感激!

【问题讨论】:

【参考方案1】:

您可以将std::set::find 与其他类型一起使用,以避免构造Item。请注意,您的集合只能包含一个具有特定位置的项目。

您可以使Position 直接与Item 进行比较(添加Item &lt; PositionPosition &lt; Item)或创建一个新的代理类:

struct ItemPosition 
    Position p;
;

inline bool operator<(const ItemPosition& l, const Item& r) 
    return l.position.x == r.position.x ? l.position.y < r.position.y : l.position.x < r.position.x;
;

inline bool operator<(const Item& l, const ItemPosition& r) 
    return l.position.x == r.position.x ? l.position.y < r.position.y : l.position.x < r.position.x;
;

// Change the comparator so it can compare with `ItemPosition` too
using ItemSet = std::set<Item, std::less<>>;

您也可以使用完全不同的比较器使PositionItem 进行比较。

struct ItemComparator 
    bool operator()(const Position& l, const Position& r) const 
        return l.x == r.x ? l.y < r.y : l.x < r.x;
    
    bool operator()(const Item& l, const Item& r) const 
        return operator()(l.position, r.position);
    
    bool operator()(const Item& l, const Position& r) const 
        return operator()(l.position, r);
    
    bool operator()(const Position& l, const Item& r) const 
        return operator()(l, r.position);
    

    using is_transparent = void;
;

using ItemSet = std::set<Item, ItemComparator>;

然后像这样使用它:

    Position findme  2, 1 ;
    // Or just `items.find(findme)` if using a custom comparator
    auto result = items.find(ItemPosition findme );
    if (result == items.end()) 
        // No item found
     else 
        Item& item = *result;
        // found item
    

【讨论】:

我假设是这样,但std::set::find 是否利用集合的排序特性进行搜索? @Addy 是的,它在日志时间内运行

以上是关于使用 `std::equal_range` 和 `boost::transform_iterator`的主要内容,如果未能解决你的问题,请参考以下文章

使用std :: equal_range查找字符串向量中出现的前缀范围

使用java加密和解密密码使用啥API和算法

如何使用 php 和 mysql 使用纬度和经度进行几何搜索

Cocoa - 为啥使用 NSInteger 和 CGFloat 而不是使用 int 和 float,或者总是使用 NSNumber?

HTTPS和SSH方式的区别和使用

学习和使用SVN和GitHub——开篇