Возможно ли, чтобы контейнер boost multi_index индексировал один элемент с 2 ключевыми значениями?

#c #boost #boost-multi-index

Вопрос:

Я хочу, чтобы мой контейнер boost multi_index индексировал один элемент с несколькими ключевыми значениями в одном индексе. Возможно ли это?

 struct Student {
    int Id;
    std::unordred_set<std::string> Clubs;
};
 

Предположим, что этот студент принадлежит к технологическим и киноклубам, и у меня есть уникальный хэшированный индекс по идентификатору и не-уникальный хэшированный индекс по клубам (я хочу знать, какие студенты в каждом клубе, посмотрев на название клуба).

Я хочу иметь возможность найти одного и того же студента, выполнив поиск по «Технологии» или «Фильму» с помощью boost multi_index. Возможно ли это с помощью boost или мне нужно развернуть собственное хранилище данных?

Ответ №1:

Вы не можете сделать это с помощью мультииндекса, содержащего ваш Student тип, но вы можете использовать (что-то на его основе) с другим типом.

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

Комментарии:

1. Ах, бимап, действительно.

Ответ №2:

Да, у вас могут быть ключи с несколькими значениями (например, ваш набор). Вы также можете несколько раз включать один и тот же элемент в один и тот же контейнер: везде, где вы пишете multi_index_container<T, ...> , вы можете записать это как multi_index_container<T*, ...> или multi_index_container<reference_wrapper<T>, ...> .

Однако это не обеспечивает дополнительных требований к поиску.

Вы обычно моделируете свою таблицу как таблицу отношений, поэтому у вас могут быть некоторые записи «в форме», такие как:

Студенческий билет Ключ от Клуба
1 «Технология»
1 «Кино»

Вы можете смоделировать Student тип, чтобы он не содержал членство в клубе напрямую. Вместо этого вы можете запросить это из той же таблицы отношений.

Комментарии:

1. Я думаю, что прямой ответ на «один элемент с несколькими ключевыми значениями» — нет

2. @Калет Ммм. Да, я прочитал это как «можем ли мы поместить один и тот же элемент несколько раз», что возможно, но все они, естественно, будут иметь одинаковые свойства

3. Немного перефразировано для ясности

Ответ №3:

Развивая ответ Sehe, это реализация идеи таблицы отношений с использованием Boost.Летный вес для удержания отдельных объектов:

Live Coliru Demo

 #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::stringamp; name="",const std::stringamp; surname=""):
    id{id},name{name},surname{surname}{}
    
  int         id;
  std::string name;
  std::string surname; 
};

using student=flyweight<
  key_value<int,student_impl,key<amp;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<amp;club_student_row::first>>,
    hashed_non_unique<key<amp;club_student_row::second>>
  >
>;

club_student_table club_student;

template<typename Student,typename... Strs>
void add_to_clubs(const Studentamp; s,const Strsamp;... strs)
{
  (club_student.emplace(strs,s),...);
}

void print_students_in_club(const clubamp; c)
{
  std::cout<<c<<": ";
  for(const autoamp; [_,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 studentamp; s)
{
  std::cout<<s.get().name<<" "<<s.get().surname<<": ";
  for(const autoamp; [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;