反向搜索& Multi_Index容器中的find_next函数

时间:2014-02-10 12:42:34

标签: c++ search boost multi-index

我有一个像这样的boost multi_index容器:

typedef multi_index_container<
    MyData, 
        indexed_by<    
            random_access<>,  // keep insertion order
            ordered_non_unique< member<MyData, time_t, &MyData::timestamp> >
        > 
> myContType;

typedef myContType::nth_index<1>::type myContType_by_time;

和搜索方法:

unsigned long searchByTimestamp(time_t timestamp) 
{   

    myContType_by_time& idIndex = myCont.get<1>();
    myContType_by_time::iterator itTime = idIndex.find(timestamp);

    if (itTime == idIndex.end())
        return 0;

    // change the index from timestamp to insertionoder(id) 
    myContType::const_iterator itId = myCont.project<0>(itTime);

    return itTime->id; 
} 

我使用时间戳(get<1> index)进行搜索并且它有效,但它从第一个(最旧的)数据开始搜索。我想根据插入顺序(get<0> index)从最后添加的(最新)数据开始。我尝试了这个代码,但它没有用。

myCont.rearrange(get<0>(myCont).rbegin());

第一个问题:有没有办法从最后输入的数据开始搜索(根据INSERTION ORDER而不是TIMESTAMP我的意思是得到&lt; 0&gt;索引)

第二个问题:如果找到的数据不是我想要的,我怎样才能继续从当前位置/索引进行搜索?我的意思是有像find_next这样的方法吗? (我在文档上找不到它)

我正在使用boost版本1.47.0开发Visual Studio 2008。

感谢。

2 个答案:

答案 0 :(得分:1)

您应该只使用std::find中的<algorithm>以及第一个索引中的反向迭代器:

unsigned long searchByTimestamp(Time_t timestamp) 
{   
    auto& idIndex = myCont.get<0>();

    auto itTime = std::find_if(
                idIndex.rbegin(), idIndex.rend(), 
                [=](MyData const& item) { return item.timestamp == timestamp; }
            );

    if (itTime == idIndex.rend())
        return 0;

    return itTime->id; 
} 

注意:如果要将反向迭代器“投影”到(前向)迭代器,请在反向迭代器上使用.base()

查看 Live On Coliru


现在,我真的不知道你需要 continue searching from the "current" position 的功能(我的意思是,找到要么返回匹配,要么rend(),所以会有没有什么可继续的)。但是,否则,您可以执行类似的操作(请参阅 Live On Coliru :)

unsigned long searchByTimestamp(Time_t timestamp) 
{   
    auto& idIndex = myCont.get<0>();

    auto current = std::find_if(idIndex.rbegin(), idIndex.rend(), 
            [=](MyData const& item) { return item.timestamp >= timestamp; });

    if (current != idIndex.rend())
    {
        bool some_extra_condition = current->timestamp == timestamp; // exact match?

        if (some_extra_condition)
            return current->id; // we have an exact match
    } else
    {
        // otherwise look for the next item that has an id divisible by 3 (3,6,9,...)
        auto alternative = std::find_if(current, idIndex.rend(), 
            [=](MyData const& item) { return (item.id % 3) == 0; });

        if (alternative != idIndex.rend())
            return alternative->id;
    }

    return 0;
} 

我编写了“替代”匹配谓词的完全愚蠢的例子。正如您所看到的,它是所有普通的 STL算法用法。这是可能的,因为算法通过迭代器与容器分离。

完整代码

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

using namespace boost::multi_index;
static int idgen = 0;

enum Time_t { last_month, last_week, yesterday, today, tomorrow };
std::ostream& operator<<(std::ostream& os, Time_t tt) {
    switch(tt)
    {
        case last_month: return os << "last_month";
        case last_week:  return os << "last_week";
        case yesterday:  return os << "yesterday";
        case today:      return os << "today";
        case tomorrow:   return os << "tomorrow";
        default: return os << "?";
    };
}

struct MyData
{
    int id = ++idgen;

    MyData(Time_t timestamp) : timestamp(timestamp) {}
    Time_t timestamp;

    friend std::ostream& operator<<(std::ostream& os, MyData const& md)
    {
        return os << "(id:" << md.id << ", timestamp:" << md.timestamp << ")";
    }
};

typedef multi_index_container<
    MyData, 
        indexed_by<    
            random_access<>,  // keep insertion order
            ordered_non_unique< member<MyData, Time_t, &MyData::timestamp> >
        > 
> myContType;

typedef myContType::nth_index<1>::type myContType_by_time;

myContType myCont;

unsigned long searchByTimestamp(Time_t timestamp) 
{   
    auto& idIndex = myCont.get<0>();

    auto itTime = std::find_if(
                idIndex.rbegin(), idIndex.rend(), 
                [=](MyData const& item) { return item.timestamp == timestamp; }
            );

    if (itTime == idIndex.rend())
        return 0;

    return itTime->id; 
} 

#include <iostream>

int main()
{
    myCont.emplace_back(Time_t(last_week));
    myCont.emplace_back(Time_t(tomorrow));
    myCont.emplace_back(Time_t(last_month));
    myCont.emplace_back(Time_t(yesterday));

    std::cout << "Insertion order:\n";
    for (auto const& item : myCont)
        std::cout << item << "\n";

    std::cout << searchByTimestamp(today)     << "\n";
    std::cout << searchByTimestamp(last_month) << "\n";
}

答案 1 :(得分:1)

您是否考虑过多次使用upper_bound

unsigned long searchByTimestamp(time_t timestamp) 
{   

    myContType_by_time& idIndex = myCont.get<1>();
    myContType_by_time::iterator itTime = idIndex.upper_bound(timestamp);

    if (itTime == idIndex.end())
        return 0;

    if (itTime != idIndex.begin()){
       myContType_by_time::iterator prev = itTime;
       --prev;
       if(prev->timestamp == timestamp) itTime=prev;
    }

    // change the index from timestamp to insertionoder(id) 
    myContType::const_iterator itId = myCont.project<0>(itTime);

    return itTime->id; 
}