2015-11-03 102 views
4

能否给我一个提示,是否有一种简单的方法,使用标准的stl或boost容器来模拟一个SQL表结构,并且能够按多列(和也许有聚集索引)?例如,一些东西来支持一个给定的表,按类型,颜色,重量分选:如何在C++中实现一个类似SQL的容器

ID Type Color Weight Hex 
1 1  NB  3.5  12 
2 1  NB  3.5  14 
3 1  NB  3.8  03 
4 1  PP  4.0  10 
5 2  DP  3.5  15 
6 2  O  5.0  12 
7 2  O  6.0  09 

谢谢

+1

首先,你需要某种*结构*的每一行。然后你可以对行使用一些[* container *](http://en.cppreference.com/w/cpp/container)。从那开始。 –

回答

6

我会使用Boost MultiIndex容器。让我画了一个样本:

Live On Coliru

#include <boost/multi_index_container.hpp> 
#include <boost/multi_index/member.hpp> 
#include <boost/multi_index/ordered_index.hpp> 
#include <boost/multi_index/hashed_index.hpp> 
#include <boost/multi_index/random_access_index.hpp> 
#include <boost/multi_index/composite_key.hpp> 
#include <boost/multi_index/sequenced_index.hpp> 
#include <vector> 

enum class color_t { NB, PP, DP, O }; 

struct Record { 
    int  ID; 
    int  Type; 
    color_t Color; 
    double Weight; 
    uint8_t Hex; 
}; 

namespace bmi = boost::multi_index; 

using Table = boost::multi_index_container< 
    Record, 
    bmi::indexed_by< 
     bmi::sequenced<bmi::tag<struct byInsertion> >, 
     bmi::ordered_unique<bmi::tag<struct byID>, bmi::member<Record, int, &Record::ID> >, 
     bmi::hashed_non_unique<bmi::tag<struct byType>, bmi::member<Record, int, &Record::Type> >, 
     bmi::ordered_non_unique<bmi::tag<struct byDetails>, 
      bmi::composite_key<Record, 
       bmi::member<Record, color_t, &Record::Color>, 
       bmi::member<Record, uint8_t, &Record::Hex>, 
       bmi::member<Record, double, &Record::Weight> 
      > 
     >, 
     bmi::random_access<bmi::tag<struct byCustomRandomAccess> > 
    > 
>; 

#include <boost/range/adaptors.hpp> // lazy demo purposes 
#include <boost/range/algorithm.hpp> 
#include <boost/range/algorithm_ext.hpp> 
#include <iostream> 

using namespace boost::adaptors; 


int main() { 
    auto getId = [](auto& r) { return r.ID; }; 

    auto dump = [](auto&& range) -> auto& { 
     for (auto&& v:range) std::cout << v << " "; 
     return std::cout; 
    }; 

    Table table { 
     Record { 4, 1, color_t::PP, 4.0, 0x10 }, 
     Record { 3, 1, color_t::NB, 3.8, 0x03 }, 
     Record { 7, 2, color_t::O, 6.0, 0x09 }, 
     Record { 1, 1, color_t::NB, 3.5, 0x12 }, 
     Record { 2, 1, color_t::NB, 3.5, 0x14 }, 
     Record { 5, 2, color_t::DP, 3.5, 0x15 }, 
     Record { 6, 2, color_t::O, 5.0, 0x12 }, 
    }; 

    using namespace boost; 

    std::cout << "Insertion order: "; 
    dump(table | transformed(getId)) << "\n"; 

    std::cout << "byID: "; 
    dump(table.get<byID>() | transformed(getId)) << "\n"; 

    std::cout << "Type 2: "; 
    dump(
     make_iterator_range(table.get<byType>().equal_range(2)) 
     | transformed(getId)) << "\n"; 

    auto& query = table.get<byDetails>(); 

    std::cout << "Color == NB, Hex = [0x00..0x0f]: "; 
    { 
     auto lb = query.upper_bound(make_tuple(color_t::NB, 0x00)); 
     auto ub = query.upper_bound(make_tuple(color_t::NB, 0x0f)); 

     dump(make_iterator_range(lb, ub) | transformed(getId)) << "\n"; 
    } 

    std::cout << "Color == NB: "; 
    dump(make_iterator_range(query.equal_range(make_tuple(color_t::NB))) | transformed(getId)) << "\n"; 

    // adhoc order: 
    { 
     auto& adhoc = table.get<byCustomRandomAccess>(); 

     std::vector<reference_wrapper<Record const>> tmp(adhoc.begin(), adhoc.end()); 

     // random shuffle, e.g.: 
     std::random_shuffle(tmp.begin(), tmp.end()); 

     // OR: use some crazy order 
     auto craziness = [](Record const& a, Record const& b) 
       { return (a.ID - 10*a.Type) < (b.ID - 10*b.Type); }; 

     sort(tmp, craziness); 

     // optionally, reflect that order back into the `byCustomRandomAccess` index: 
     adhoc.rearrange(tmp.begin()); 
    } 

    std::cout << "Custom order persisted: "; 
    dump(table.get<byCustomRandomAccess>() | transformed(getId)) << "\n"; 
} 

打印:

Insertion order: 4 3 7 1 2 5 6 
byID: 1 2 3 4 5 6 7 
Type 2: 6 5 7 
Color == NB, Hex = [0x00..0x0f]: 3 
Color == NB: 3 1 2 
Custom order persisted: 5 6 7 1 2 3 4 
+0

下面是我编码示例的实况流:https://www.livecoding.tv/video/table-like-datastructure免 - 加强-多指标/([实验](http://chat.stackoverflow.com/transcript/10?m=24182469#24182469)) – sehe

+0

谢谢!你让它看起来很容易)) – Qwertypal

+0

干杯!如果你知道如何使用它们,Boost库很不错。我使用它们进行快速原型设计。根据规格/要求,我会在这里推荐不同的解决方案(Postgres,sqlite,sqlite +加密等)。内存映射数据结构经常为原型而胜利。 – sehe

0

我会使用std::tuplestd::vector

using sql_table_1 = std::vector<std::tuple<size_t,size_t,Color,float,size_t>> 

的顺序排序,您可以用std::sort +成本比较器进行排序,例如,我们按照weight排序:

sql_table_1 table {/*...populate...*/}; 
using row = std::tuple<size_t,size_t,Color,float,size_t>; 
std::sort(table.begin(),table.end(),[](const row& row1, const row& row2){ 
    return std::get<3>(row1) < std::get<3>(row2); 
}); 
+0

谢谢,但虽然一些列是固定的,我需要能够按多列对 – Qwertypal

+0

进行排序,所以给它一个成本高昂的比较器,它可以...并使用std :: array代替 –

+0

为什么用“元组”代替一个'struct'还是一个'class'? –

0

这使我头上的第一自然的方式是使用模板+类。您的类将举行预先定义的字段(例如int IDint Type等)。你可以重载排序功能与模板参数类,这样你可以调用像instance.SortBy<field>()。这将要求您创建单独的一套方法,你想不同的类中的每个时间字段,所以一段时间后,它可以变得相当繁琐,但对于小任务也可能是足够的。现在使用现有的库可能会容易得多,但如果我对预定义的数据有一些小任务,我可能会使用这个解决方案。

+0

是的,它现在看起来很乏味。我希望这是一个现有解决方案的常见问题......但假设我不能逃避那个 – Qwertypal

相关问题