如何使用组合键获取boost::multi_index_container中第一个键的不同计数

How to get the distinct count of first key in boost::multi_index_container with composite key

本文关键字:第一个 container boost 获取 何使用 multi index 组合      更新时间:2023-10-16

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的关系数据库中,有任何方法可以获得非唯一索引键的不同计数吗?以及如何获得Roster复合密钥(Person::m_namePerson::m_id)的第一个密钥(Person::name)的不同计数?THX!

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

您可以利用这样一个事实,即您知道复合索引是按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
        );

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

Demo

在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

另一种可能的方法,如果有许多元素具有相同的键,可能会更快,包括使用upper_bound:跳过索引

在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";
}