如何使用复合键获取boost :: multi_index_container中第一个键的明确计数

时间:2015-06-22 08:56:03

标签: c++ boost multi-index

boost::multi_index_container支持构建容器,维护一个或多个具有不同排序和访问语义的索引,如关系数据库。 我使用boost::multi_index_container复合键来处理这样的事情:

struct Person {
    Person(int id, string name):
        m_id(id),
        m_name(name)
    {
    }

    int m_id;
    string m_name;
};

typedef multi_index_container<
    Person,
    indexed_by<
        ordered_unique<
            member<Person, int, &Person::m_id>
        >,
        ordered_unique<
            composite_key<
                Person,
                member<Person, string, &Person::m_name>,
                member<Person, int, &Person::m_id>
            >
         >
    >
> Roster;

int main()
{
    Roster r;
    r.insert(Person(1, "Tom"));
    r.insert(Person(2, "Jack"));
    r.insert(Person(3, "Tom"));
    r.insert(Person(4, "Leo"));

    /* The distinct count of name must be 3, and how to get it? */
}

这是否可以在boost::multi_index_container关系数据库中获取非唯一索引键的不同计数?如何获得Person::name复合键(RosterPerson::m_name)的第一个键(Person::m_id)的不同计数? THX!

编辑: 或者这是一种只是迭代不同的第一个键的方法?这样我们就可以得到第一把钥匙的明显计数。

2 个答案:

答案 0 :(得分:3)

您可以利用这样的事实,即您知道复合索引首先按m_name排序。

这意味着您可以在其中运行标准的“唯一”,而无需额外的排序步骤:

    size_t unique_names = boost::size(r.get<by_name_id>() 
            | transformed([](Person const& p) -> std::string const& { return p.m_name; })
            | uniqued
        );

这可能是一个很好的时间/存储权衡。

演示

<强> Live On Coliru

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>

struct Person {
    Person(int id, std::string name):
        m_id(id),
        m_name(name)
    {
    }

    int m_id;
    std::string m_name;
};

namespace bmi = boost::multi_index;

typedef boost::multi_index_container<
    Person,
    bmi::indexed_by<
        bmi::ordered_unique<
            bmi::member<Person, int, &Person::m_id>
        >,
        bmi::ordered_unique<
            bmi::tag<struct by_name_id>,
            bmi::composite_key<
                Person,
                bmi::member<Person, std::string, &Person::m_name>,
                bmi::member<Person, int, &Person::m_id>
            >
        >
    >
> Roster;

#include <iostream>
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>

using boost::adaptors::transformed;
using boost::adaptors::uniqued;

int main()
{
    Roster r;
    r.insert(Person(1, "Tom"));
    r.insert(Person(2, "Jack"));
    r.insert(Person(3, "Tom"));
    r.insert(Person(4, "Leo"));

    size_t unique_names = boost::size(r.get<by_name_id>() 
            | transformed([](Person const& p) -> std::string const& { return p.m_name; })
            | uniqued
        );

    std::cout << unique_names;
}

打印

3

答案 1 :(得分:2)

另一种可能性,如果有许多具有相同密钥的元素可能更快,则涉及使用upper_bound跳过索引:

<强> Live On Coliru

template<typename Index,typename KeyExtractor>
std::size_t distinct(const Index& i,KeyExtractor key)
{
  std::size_t res=0;
  for(auto it=i.begin(),it_end=i.end();it!=it_end;){
    ++res;
    it=i.upper_bound(key(*it));
  }
  return res;
}

int main()
{
    Roster r;
    r.insert(Person(1, "Tom"));
    r.insert(Person(2, "Jack"));
    r.insert(Person(3, "Tom"));
    r.insert(Person(4, "Leo"));

    auto d=distinct(r.get<1>(),[](const Person& p){return std::cref(p.m_name);});
    std::cout<<d<<"\n";
}