C++ 通过自定义顺序迭代boost multi_索引

C++ 通过自定义顺序迭代boost multi_索引,c++,boost,containers,boost-multi-index,C++,Boost,Containers,Boost Multi Index,我有一个包含多个索引的boostmulti_index容器。如何在迭代时使用指定的自定义比较来迭代元素 例如,假定Element::name和Element::index由multi_index容器索引 bool myCompare(const Element &lhs, const Element &rhs) { if(lhs.name == rhs.name) { return lhs.index < rhs.index; }

我有一个包含多个索引的boost
multi_index
容器。如何在迭代时使用指定的自定义比较来迭代元素

例如,假定
Element::name
Element::index
multi_index
容器索引

bool myCompare(const Element &lhs, const Element &rhs)
{
    if(lhs.name == rhs.name)
    {
        return lhs.index < rhs.index;
    }
    else
    {
        return lhs.name < rhs.name;
    }
}
bool myCompare(常量元素和lhs、常量元素和rhs)
{
if(lhs.name==rhs.name)
{
返回lhs.index

但是,迭代不应限于上述情况,而是允许根据元素的索引成员进行任何类型的排序,类似于SQL SELECT排序。

这不是多索引容器的功能

但是,您可以轻松创建额外的临时索引:

std::vector<boost::reference_wrapper<Element const> > temporary(table.begin(), table.end());
奖金:使用
重新排列
,您可以轻松地在
多索引::随机访问
索引中保持排序:

table.get<external>().rearrange(temporary.begin());
演示

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>

struct Element {
    int index;
    std::string name;
};

#include <tuple>
bool myCompare(const Element &lhs, const Element &rhs) {
    return std::tie(lhs.name, lhs.index) < std::tie(rhs.name, rhs.index);
}

namespace bmi = boost::multi_index;

using Table = boost::multi_index_container<Element,
      bmi::indexed_by<
        bmi::random_access<bmi::tag<struct external> >
      > >;

#include <iostream>
#include <vector> // for the temporary index

int main() {
    Table table;

    // generate 30 random records...
    std::generate_n(back_inserter(table), 30,
            []{ return Element { rand()%100, std::string(1, 'a'+rand()%26) }; }
        );

    {
        // temporary index:
        std::vector<boost::reference_wrapper<Element const> > temporary(table.begin(), table.end());

        // iterate table in the order specified by myCompare:
        std::sort(temporary.begin(), temporary.end(), myCompare);

        for(Element const& e: temporary)
            std::cout << e.index << "\t" << e.name << "\n";

        // now to rearrange a random-access index on the multi-index container:
        table.get<external>().rearrange(temporary.begin());
    }
}
using Table = boost::multi_index_container<Element,
    bmi::indexed_by<
        bmi::sequenced<bmi::tag<struct insertion_order> >,
        // ready made index for traversal in composite order
        bmi::ordered_non_unique<bmi::tag<struct readymade>, 
            bmi::composite_key<Element,
                bmi::member<Element, std::string, &Element::name>,
                bmi::member<Element, int, &Element::index> 
            >
        >
    > >;

int main() {
    // generate 30 random records...
    Table table;
    std::generate_n(back_inserter(table), 30, []{ return Element { rand()%100, std::string(1, 'a'+rand()%26) }; });

    // effectively "zero" cost iteration there:
    for(Element const& e: table.get<readymade>())
        std::cout << e.index << "\t" << e.name << "\n";
}
您可以看到,在名称相等的地方,较低的索引排在第一位


更新评论内容

嗯?你是要魔法仙尘吗

你是要魔法仙尘吗?没有魔法

DBMS不使用任何异常的东西。它们通常使用BTrees,非常类似于花园中的数据结构 多样性
std::map
,或者实际上是
bmi::ordered_u[non_u]唯一的
索引。因此,在这方面,Boost MultiIndex是(接近)您想要的, 已经

RDBMS es给表带来的主要附加功能是持久性。这样,一切都变得更有用、更具可扩展性和。。。较少的 效率高

所以,不要把DBMS看作效率的圣杯

内存中的键值数据存储被广泛用于提高性能是有原因的。另一个重要的注意事项是检索 SQL中的有序结果集的性能根本不好,除非索引已经存在

现在,如果您希望获得尽可能好的性能,您可能需要设计自己的数据结构(可能需要借助Boost) 但鉴于您提出这些问题的程度,我会在之前的一段较长时间内使用Boost Multi Index 是的。只需创建有时可能需要组合的索引,并编写一些“循环代码”,根据需要组合它们

思想 现在开箱思考,您可能想知道如何“轻松”实现两级排序,使DBMS 引擎可能会

  • 与DBMS引擎一样,最简单的方法是随时准备一个始终最新的索引:

    #include <boost/multi_index_container.hpp>
    #include <boost/multi_index/random_access_index.hpp>
    
    struct Element {
        int index;
        std::string name;
    };
    
    #include <tuple>
    bool myCompare(const Element &lhs, const Element &rhs) {
        return std::tie(lhs.name, lhs.index) < std::tie(rhs.name, rhs.index);
    }
    
    namespace bmi = boost::multi_index;
    
    using Table = boost::multi_index_container<Element,
          bmi::indexed_by<
            bmi::random_access<bmi::tag<struct external> >
          > >;
    
    #include <iostream>
    #include <vector> // for the temporary index
    
    int main() {
        Table table;
    
        // generate 30 random records...
        std::generate_n(back_inserter(table), 30,
                []{ return Element { rand()%100, std::string(1, 'a'+rand()%26) }; }
            );
    
        {
            // temporary index:
            std::vector<boost::reference_wrapper<Element const> > temporary(table.begin(), table.end());
    
            // iterate table in the order specified by myCompare:
            std::sort(temporary.begin(), temporary.end(), myCompare);
    
            for(Element const& e: temporary)
                std::cout << e.index << "\t" << e.name << "\n";
    
            // now to rearrange a random-access index on the multi-index container:
            table.get<external>().rearrange(temporary.begin());
        }
    }
    
    using Table = boost::multi_index_container<Element,
        bmi::indexed_by<
            bmi::sequenced<bmi::tag<struct insertion_order> >,
            // ready made index for traversal in composite order
            bmi::ordered_non_unique<bmi::tag<struct readymade>, 
                bmi::composite_key<Element,
                    bmi::member<Element, std::string, &Element::name>,
                    bmi::member<Element, int, &Element::index> 
                >
            >
        > >;
    
    int main() {
        // generate 30 random records...
        Table table;
        std::generate_n(back_inserter(table), 30, []{ return Element { rand()%100, std::string(1, 'a'+rand()%26) }; });
    
        // effectively "zero" cost iteration there:
        for(Element const& e: table.get<readymade>())
            std::cout << e.index << "\t" << e.name << "\n";
    }
    
  • 或者,您可以定义单独的索引,并将它们与您自己的算法一起使用,以实现两级排序:

    using Table = boost::multi_index_container<Element,
        bmi::indexed_by<
            bmi::sequenced<bmi::tag<struct insertion_order> >,
    
            // separate indices that we might combine in some way later::
            bmi::ordered_non_unique<bmi::tag<struct by_index>, bmi::member<Element, int, &Element::index> >,
            bmi::ordered_non_unique<bmi::tag<struct by_name>,  bmi::member<Element, std::string, &Element::name> >
        > >;
    
    使用Table=boost::multi_index_container>;
    
    现在,组合索引成为“引擎”的工作,或者,在本例中是您的算法。这里有一个想法:

    template <typename Index1, typename Index2, typename Table, typename Function>
        void SelectOrderBy2(Table const& table, Function function) {
    
            using T = typename Table::value_type const;
            auto& idx1 = table.template get<Index1>();
            auto& idx2 = table.template get<Index2>();
    
            auto it = idx1.begin(), end = idx1.end();
    
            while (it!=end) {
                auto next = idx1.upper_bound(idx1.key_extractor()(*it));
    
                std::set<boost::reference_wrapper<T>, typename Table::template index<Index2>::type::value_compare>
                    set(idx2.value_comp());
    
                while (it != next)
                    set.insert(set.end(), boost::cref(*it++));
    
                for (auto& e: set)
                    function(e);
            }
        }
    
    模板
    void SelectOrderBy2(表常量和表、函数){
    使用T=typename表::value\u type const;
    auto&idx1=table.template get();
    auto&idx2=table.template get();
    auto it=idx1.begin(),end=idx1.end();
    while(it!=结束){
    auto-next=idx1.upper_-bound(idx1.key_提取器()(*it));
    std::set
    set(idx2.value_comp());
    while(it!=下一个)
    set.insert(set.end(),boost::cref(*it++);
    用于(自动和电气:设置)
    职能(e);
    }
    }
    
    这是一些非常容易出错的模板代码,但您可以非常简单地使用它:

    SelectOrderBy2<by_name, by_index>(
            table, 
            [](Element const& e) { std::cout << e.index << "\t" << e.name << "\n"; }
        );
    
    选择OrderBy2(
    桌子
    
    [](Element const&e){std::cout这不是多索引容器的特性

    但是,您可以轻松创建额外的临时索引:

    std::vector<boost::reference_wrapper<Element const> > temporary(table.begin(), table.end());
    
    奖金:使用
    重新排列
    ,您可以轻松地在
    多索引::随机访问
    索引中保持排序:

    table.get<external>().rearrange(temporary.begin());
    
  • 演示

    #include <boost/multi_index_container.hpp>
    #include <boost/multi_index/random_access_index.hpp>
    
    struct Element {
        int index;
        std::string name;
    };
    
    #include <tuple>
    bool myCompare(const Element &lhs, const Element &rhs) {
        return std::tie(lhs.name, lhs.index) < std::tie(rhs.name, rhs.index);
    }
    
    namespace bmi = boost::multi_index;
    
    using Table = boost::multi_index_container<Element,
          bmi::indexed_by<
            bmi::random_access<bmi::tag<struct external> >
          > >;
    
    #include <iostream>
    #include <vector> // for the temporary index
    
    int main() {
        Table table;
    
        // generate 30 random records...
        std::generate_n(back_inserter(table), 30,
                []{ return Element { rand()%100, std::string(1, 'a'+rand()%26) }; }
            );
    
        {
            // temporary index:
            std::vector<boost::reference_wrapper<Element const> > temporary(table.begin(), table.end());
    
            // iterate table in the order specified by myCompare:
            std::sort(temporary.begin(), temporary.end(), myCompare);
    
            for(Element const& e: temporary)
                std::cout << e.index << "\t" << e.name << "\n";
    
            // now to rearrange a random-access index on the multi-index container:
            table.get<external>().rearrange(temporary.begin());
        }
    }
    
    using Table = boost::multi_index_container<Element,
        bmi::indexed_by<
            bmi::sequenced<bmi::tag<struct insertion_order> >,
            // ready made index for traversal in composite order
            bmi::ordered_non_unique<bmi::tag<struct readymade>, 
                bmi::composite_key<Element,
                    bmi::member<Element, std::string, &Element::name>,
                    bmi::member<Element, int, &Element::index> 
                >
            >
        > >;
    
    int main() {
        // generate 30 random records...
        Table table;
        std::generate_n(back_inserter(table), 30, []{ return Element { rand()%100, std::string(1, 'a'+rand()%26) }; });
    
        // effectively "zero" cost iteration there:
        for(Element const& e: table.get<readymade>())
            std::cout << e.index << "\t" << e.name << "\n";
    }
    
    您可以看到,在名称相等的地方,较低的索引排在第一位


    更新评论内容

    嗯?你是要魔法仙尘吗

    你是要魔法仙尘吗?没有魔法

    数据库管理系统不会使用任何不寻常的东西。它们通常使用BTrees,非常类似于花园中的数据结构 多样性
    std::map
    ,或者实际上是
    bmi::ordered_uu[non_u]unique
    索引。因此,在这方面,Boost MultiIndex是(接近)您想要的, 已经

    RDBMS es给表带来的主要附加功能是持久性。有了持久性,一切都变得更有用、更具可扩展性和…更少 效率高

    所以,不要把DBMS看作效率的圣杯

    内存中的键值数据存储被广泛用于性能方面是有原因的 SQL中的有序结果集的性能根本不好,除非索引已经存在

    现在,如果您希望获得尽可能好的性能,您可能需要设计自己的数据结构(可能需要借助Boost) 但鉴于您提出这些问题的程度,我会在之前的一段较长时间内使用Boost Multi Index 可以。只需创建有时需要合并的索引,并编写一些“循环代码”,根据需要合并它们

    思想 现在开箱思考,您可能想知道如何“轻松”实现两级排序,使DBMS 引擎可能会

  • 与DBMS引擎一样,最简单的方法是随时准备一个始终最新的索引:

    #include <boost/multi_index_container.hpp>
    #include <boost/multi_index/random_access_index.hpp>
    
    struct Element {
        int index;
        std::string name;
    };
    
    #include <tuple>
    bool myCompare(const Element &lhs, const Element &rhs) {
        return std::tie(lhs.name, lhs.index) < std::tie(rhs.name, rhs.index);
    }
    
    namespace bmi = boost::multi_index;
    
    using Table = boost::multi_index_container<Element,
          bmi::indexed_by<
            bmi::random_access<bmi::tag<struct external> >
          > >;
    
    #include <iostream>
    #include <vector> // for the temporary index
    
    int main() {
        Table table;
    
        // generate 30 random records...
        std::generate_n(back_inserter(table), 30,
                []{ return Element { rand()%100, std::string(1, 'a'+rand()%26) }; }
            );
    
        {
            // temporary index:
            std::vector<boost::reference_wrapper<Element const> > temporary(table.begin(), table.end());
    
            // iterate table in the order specified by myCompare:
            std::sort(temporary.begin(), temporary.end(), myCompare);
    
            for(Element const& e: temporary)
                std::cout << e.index << "\t" << e.name << "\n";
    
            // now to rearrange a random-access index on the multi-index container:
            table.get<external>().rearrange(temporary.begin());
        }
    }
    
    using Table = boost::multi_index_container<Element,
        bmi::indexed_by<
            bmi::sequenced<bmi::tag<struct insertion_order> >,
            // ready made index for traversal in composite order
            bmi::ordered_non_unique<bmi::tag<struct readymade>, 
                bmi::composite_key<Element,
                    bmi::member<Element, std::string, &Element::name>,
                    bmi::member<Element, int, &Element::index> 
                >
            >
        > >;
    
    int main() {
        // generate 30 random records...
        Table table;
        std::generate_n(back_inserter(table), 30, []{ return Element { rand()%100, std::string(1, 'a'+rand()%26) }; });
    
        // effectively "zero" cost iteration there:
        for(Element const& e: table.get<readymade>())
            std::cout << e.index << "\t" << e.name << "\n";
    }
    
  • 或者,您可以定义单独的索引,并且