我有一个像这样的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。
感谢。
答案 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()
。
现在,我真的不知道你需要 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;
}