是否可以让 boost multi_index 容器索引一个具有 2 个键值的元素?
Is it possible to have boost multi_index container index one element with 2 key values?
我想让我的 boost multi_index 容器索引一个元素,该元素在同一索引上具有多个键值。这可能吗?
struct Student {
int Id;
std::unordred_set<std::string> Clubs;
};
假设这个学生属于技术和电影俱乐部,我在 Id 上有唯一的散列索引,在俱乐部上有 non_unique 散列索引(我想通过查看俱乐部名称了解每个俱乐部有哪些学生) .
我希望能够通过使用 boost multi_index 搜索“技术”或“电影”来找到同一位学生。可以使用 boost 还是我需要滚动我自己的数据存储?
是的,您可以拥有具有多个值的键(例如您的集合)。您还可以在同一容器中多次包含同一元素:无论您在哪里写 multi_index_container<T, ...>
,您都可以将其写为 multi_index_container<T*, ...>
或 multi_index_container<reference_wrapper<T>, ...>
.
但是这不提供额外的查找要求。
您通常会将 table 建模为关系 table,因此您可以将一些记录“塑造”为:
Student Id
Club Key
1
"Technology"
1
"Movie"
您可以为 Student
类型建模,这样它就不需要直接包含俱乐部会员资格。相反,您可以从相同的关系 table.
查询它
你不能用包含你的 Student
类型的 multi_index 来做到这一点,但你可以使用(基于它的东西)不同的类型。
using Id_t = int;
using Club_t = std::string;
using StudentClubs = boost::bimap<boost::bimap::multiset_of<Id_t>, boost::bimap::multiset_of<Club_t>>;
StudentClubs student_clubs = /* some data */;
然后您可以查找电影俱乐部中的所有学生
for (auto [club, student] : boost::iterator_range(student_clubs.right.equal_range("movie"))) {
std::cout << student;
}
或者学生 3 所在的所有俱乐部
for (auto [student, club] : boost::iterator_range(student_clubs.left.equal_range(3))) {
std::cout << club;
}
详细说明 Sehe 的回答,这是关系 table 想法的实现,它使用 Boost.Flyweight 来保存各个实体:
#include <boost/flyweight.hpp>
#include <boost/flyweight/key_value.hpp>
#include <boost/flyweight/no_tracking.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/key.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>
#include <string>
#include <utility>
using namespace boost::flyweights;
using namespace boost::multi_index;
struct student_impl
{
student_impl(
int id,const std::string& name="",const std::string& surname=""):
id{id},name{name},surname{surname}{}
int id;
std::string name;
std::string surname;
};
using student=flyweight<
key_value<int,student_impl,key<&student_impl::id>>,
no_tracking
>;
using club=flyweight<std::string>;
static student::initializer sinit;
static club::initializer cinit;
using club_student_row=std::pair<club,student>;
using club_student_table=multi_index_container<
club_student_row,
indexed_by<
hashed_non_unique<key<&club_student_row::first>>,
hashed_non_unique<key<&club_student_row::second>>
>
>;
club_student_table club_student;
template<typename Student,typename... Strs>
void add_to_clubs(const Student& s,const Strs&... strs)
{
(club_student.emplace(strs,s),...);
}
void print_students_in_club(const club& c)
{
std::cout<<c<<": ";
for(const auto& [_,s]:
boost::make_iterator_range(club_student.equal_range(c))){
std::cout<<s.get().name<<" "<<s.get().surname<<"; ";
}
std::cout<<"\n";
}
void print_clubs_for_student(const student& s)
{
std::cout<<s.get().name<<" "<<s.get().surname<<": ";
for(const auto& [c,_]:
boost::make_iterator_range(club_student.get<1>().equal_range(s))){
std::cout<<c<<"; ";
}
std::cout<<"\n";
}
int main()
{
add_to_clubs(student_impl(1,"Ben"),"Technology");
add_to_clubs(student_impl(2,"Caleth"),"Technology","Movie");
add_to_clubs(student_impl(3,"Sehe"),"Technology","Latin");
add_to_clubs(student_impl(4,"Joaquin","Lopez"),"Movie","Latin");
print_students_in_club(club("Technology"));
print_clubs_for_student(student(4));
}
输出
Technology: Sehe ; Caleth ; Ben ;
Joaquin Lopez: Latin; Movie;
我想让我的 boost multi_index 容器索引一个元素,该元素在同一索引上具有多个键值。这可能吗?
struct Student {
int Id;
std::unordred_set<std::string> Clubs;
};
假设这个学生属于技术和电影俱乐部,我在 Id 上有唯一的散列索引,在俱乐部上有 non_unique 散列索引(我想通过查看俱乐部名称了解每个俱乐部有哪些学生) .
我希望能够通过使用 boost multi_index 搜索“技术”或“电影”来找到同一位学生。可以使用 boost 还是我需要滚动我自己的数据存储?
是的,您可以拥有具有多个值的键(例如您的集合)。您还可以在同一容器中多次包含同一元素:无论您在哪里写 multi_index_container<T, ...>
,您都可以将其写为 multi_index_container<T*, ...>
或 multi_index_container<reference_wrapper<T>, ...>
.
但是这不提供额外的查找要求。
您通常会将 table 建模为关系 table,因此您可以将一些记录“塑造”为:
Student Id | Club Key |
---|---|
1 | "Technology" |
1 | "Movie" |
您可以为 Student
类型建模,这样它就不需要直接包含俱乐部会员资格。相反,您可以从相同的关系 table.
你不能用包含你的 Student
类型的 multi_index 来做到这一点,但你可以使用(基于它的东西)不同的类型。
using Id_t = int;
using Club_t = std::string;
using StudentClubs = boost::bimap<boost::bimap::multiset_of<Id_t>, boost::bimap::multiset_of<Club_t>>;
StudentClubs student_clubs = /* some data */;
然后您可以查找电影俱乐部中的所有学生
for (auto [club, student] : boost::iterator_range(student_clubs.right.equal_range("movie"))) {
std::cout << student;
}
或者学生 3 所在的所有俱乐部
for (auto [student, club] : boost::iterator_range(student_clubs.left.equal_range(3))) {
std::cout << club;
}
详细说明 Sehe 的回答,这是关系 table 想法的实现,它使用 Boost.Flyweight 来保存各个实体:
#include <boost/flyweight.hpp>
#include <boost/flyweight/key_value.hpp>
#include <boost/flyweight/no_tracking.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/key.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>
#include <string>
#include <utility>
using namespace boost::flyweights;
using namespace boost::multi_index;
struct student_impl
{
student_impl(
int id,const std::string& name="",const std::string& surname=""):
id{id},name{name},surname{surname}{}
int id;
std::string name;
std::string surname;
};
using student=flyweight<
key_value<int,student_impl,key<&student_impl::id>>,
no_tracking
>;
using club=flyweight<std::string>;
static student::initializer sinit;
static club::initializer cinit;
using club_student_row=std::pair<club,student>;
using club_student_table=multi_index_container<
club_student_row,
indexed_by<
hashed_non_unique<key<&club_student_row::first>>,
hashed_non_unique<key<&club_student_row::second>>
>
>;
club_student_table club_student;
template<typename Student,typename... Strs>
void add_to_clubs(const Student& s,const Strs&... strs)
{
(club_student.emplace(strs,s),...);
}
void print_students_in_club(const club& c)
{
std::cout<<c<<": ";
for(const auto& [_,s]:
boost::make_iterator_range(club_student.equal_range(c))){
std::cout<<s.get().name<<" "<<s.get().surname<<"; ";
}
std::cout<<"\n";
}
void print_clubs_for_student(const student& s)
{
std::cout<<s.get().name<<" "<<s.get().surname<<": ";
for(const auto& [c,_]:
boost::make_iterator_range(club_student.get<1>().equal_range(s))){
std::cout<<c<<"; ";
}
std::cout<<"\n";
}
int main()
{
add_to_clubs(student_impl(1,"Ben"),"Technology");
add_to_clubs(student_impl(2,"Caleth"),"Technology","Movie");
add_to_clubs(student_impl(3,"Sehe"),"Technology","Latin");
add_to_clubs(student_impl(4,"Joaquin","Lopez"),"Movie","Latin");
print_students_in_club(club("Technology"));
print_clubs_for_student(student(4));
}
输出
Technology: Sehe ; Caleth ; Ben ;
Joaquin Lopez: Latin; Movie;