2015-11-03 39 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

相關問題