使用Boost Filter迭代器处理非基元对象

Using Boost Filter Iterator with non-Primitive Objects

本文关键字:对象 处理 Boost Filter 迭代器 使用      更新时间:2023-10-16

假设我有一个从Boost的Multi-Index返回的迭代器,其中每个记录包含一个年龄和一个名称字段。

我得到了 的迭代器
auto& index = get<age>(m_records);
auto ibegin = index.begin();
auto iend = index.end();

我如何将这个迭代器与Boost的过滤器迭代器一起使用,这样我就可以返回所有的记录,比如name = "John"?

我为谓词操作符设置了一个结构体,我不确定它是否正确:

struct name_equal_to {
      std::string struct_sname;
      bool operator()(ServerRecord x) { return x.get_name() == struct_sname; }
      name_equal_to(std::string in) : struct_sname(in){}
   };

我将使用过滤适配器,使内容更易于阅读:

for (auto& r : get<age>(m_records) | filtered(name_equal_to("John"))
    std::cout << r << "n";

我会在风格上改进函子(Live On Coliru):

struct name_equal_to {
    bool operator()(ServerRecord const& x) const { 
        return x.get_name() == sname_; 
    }
    name_equal_to(std::string in) : sname_(std::move(in)){}
  private:
    std::string sname_;
};

为了使它更简洁,使用Phoenix在适当的位置定义谓词named_john:

auto named_john = phx::bind(&record::name, arg1) == "John";

参见Live On Coliru,它打印两条按年龄索引排序的记录:

2 John 40
4 John 57

完整示例代码

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>
using boost::multi_index_container;
using namespace boost::multi_index;
struct record {
    int         id;
    std::string name;
    int         age;
    friend std::ostream& operator<<(std::ostream& os,const record& e) {
        return os << e.id << " " << e.name << " " << e.age;
    }
};
typedef multi_index_container<
  record,
  indexed_by<
    ordered_unique<tag<struct id>      , BOOST_MULTI_INDEX_MEMBER(record, int        , id)>   ,
    ordered_non_unique<tag<struct name>, BOOST_MULTI_INDEX_MEMBER(record, std::string, name)> ,
    ordered_non_unique<tag<struct age> , BOOST_MULTI_INDEX_MEMBER(record, int        , age)> >
> employee_set;

employee_set get_records()
{
    employee_set es;
    es.insert(record{ 0,       "Joe",   31 });
    es.insert(record{ 1,    "Robert",   27 });
    es.insert(record{ 2,      "John",   40 });
    // next insertion will fail, as there is an record with the same ID
    es.insert(record{ 2, "Aristotle", 2387 });
    es.insert(record{ 3,    "Albert",   20 });
    es.insert(record{ 4,      "John",   57 });
    return es;
}
#include <boost/phoenix.hpp>
#include <boost/range/adaptors.hpp>
namespace phx = boost::phoenix;
using namespace phx::arg_names;
using boost::adaptors::filtered;
int main()
{
    auto const m_records = get_records();
    auto named_john = phx::bind(&record::name, arg1) == "John";
    for (auto& r : get<age>(m_records) | filtered(named_john)) {
        std::cout << r << "n";
    };
}

@sehe的答案绝对正确,但是如果你关心效率,那么这不是按年龄排序检索所有Johns的最快方法。假设您的容器有N个元素,其中有M个 Johns。所以:

  1. 遍历所有按年龄排序并按"John"过滤的元素需要N步。
  2. 检索所有Johns并按年龄排序(如您在其他帖子中讨论的)需要(大致)2·log(N)步骤来检索Johns的范围,临时向量的一次分配,M步骤来填充它,O(M·log(M))来排序它,M遍历它。

,它是O (N )和O (log (N ) + M·日志())。我打赌#2比#1快,M <<N,我认为这是通常的情况(当然您应该测量您的实际程序)。