我有一个适配器,其目标是为配对值pair<FeatureVector, Label>
提供前向迭代器。但是在我的内部表示中,我将数据存储为vector<pair<vector<strings>, Label>>
。
所以在迭代过程中,我需要将它展平并转换每一个string
,这是一个简短的句子,就像&#34;油今天大量下降&#34;到FeatureVector
在原始变体中我有类似的东西:
{
{"Oil drops massively","OPEC surge oil produciton","Brent price goes up" -> "OIL_LABEL"},
{"France consume more vine", "vine production in Italy drops" -> "VINE_LABEL"}
}
我需要将其转换为:
{
vectorize("Oil drops massively") -> "OIL_LABEL",
vectorize("OPEC surge oil produciton") -> "OIL_LABEL", ... ,
vectorize("vine production in Italy drops") -> "VINE_LABEL"
}
vectorize()
- &gt;它是从句子到稀疏向量的转换,如"Oil drops on NYSE" -> {0,1,0..0,1,0..0,1}
最简单的方法是创建新的向量并使用所有数据初始化它,而不是使用它的迭代器,但这是非常资源的操作,所以理想情况下我希望在每次迭代时都进行这种转换。这种转换最优雅的方式是什么?
这是用于存储文本语料库的数据结构的简化版本。稍后需要在分类器初始化中使用迭代器,这需要2个迭代器:begin
和end
,它在逻辑上与vector
中的相同。
答案 0 :(得分:1)
一个简单的范围类型:
-injars /path/to/jar/project-version-sans-externalized.jar(!META-INF)
-outjars /path/to/obfuscated/jar.jar
-keepnames class com.example.ErrorHandler
-keepnames class com.example.ApplicationLoader
-keepnames class controllers.**
-keepclassmembernames class controllers.** {
<methods>;
}
-keeppackagenames controllers.**, router.**, views.**
-keep class router.** {*;}
-keepnames class router.** {*;}
-keepclassmembers class router.** {*;}
-keep class views.** {*;}
-keepnames class views.** {*;}
-keepclassmembers class views.** {*;}
-libraryjars /usr/lib/jvm/latest/jre/lib/rt.jar
-libraryjars /path/to/lib/library1.jar
-libraryjars /path/to/lib/library2.jar
这是一个不兼容的伪迭代器,它执行两个ranes的交叉乘积:
template<class It>
struct range_t {
It b{},e{};
It begin() const {return b;}
It end() const {return e;}
bool empty() const {return begin()==end();}
friend bool operator==(range_t lhs, range_t rhs){
if (lhs.empty() && rhs.empty()) return true;
return lhs.begin() == rhs.begin() && lhs.end() == rhs.end();
}
friend bool operator!=(range_t lhs, range_t rhs){
return !(lhs==rhs);
}
range_t without_front( std::size_t N = 1 ) const {
return { std::next(begin(), N), end() };
}
range_t without_back( std::size_t N = 1 ) const {
return { begin(), std::prev(end(),N) };
}
decltype(auto) front() const {
return *begin();
}
decltype(auto) back() const {
return *std::prev(end());
}
};
template<class It>
range_t<It> range( It b, It e ) {
return {b,e};
}
通过这个,您可以template<class ItA, class ItB>
struct cross_iterator_t {
range_t<ItA> cur_a;
range_t<ItB> orig_b;
range_t<ItB> cur_b;
cross_iterator_t( range_t<ItA> a, range_t<ItB> b ):
cur_a(a), orig_b(b), cur_b(b)
{}
bool empty() const { return cur_a.empty() || cur_b.empty(); }
void operator++(){
cur_b = cur_b.without_front();
if (cur_b.empty()) {
cur_a = cur_a.without_front();
if (cur_a.empty()) return;
cur_b = orig_b;
}
}
auto operator*()const {
return std::make_pair( cur_a.front(), cur_b.front() );
}
friend bool operator==( cross_iterator_t lhs, cross_iterator_t rhs ) {
if (lhs.empty() && rhs.empty()) return true;
auto mytie=[](auto&& self){
return std::tie(self.cur_a, self.cur_b);
};
return mytie(lhs)==mytie(rhs);
}
friend bool operator!=( cross_iterator_t lhs, cross_iterator_t rhs ) {
return !(lhs==rhs);
}
};
template<class Lhs, class Rhs>
auto cross_iterator( range_t<Lhs> a, range_t<Rhs> b )
-> cross_iterator_t<Lhs, Rhs>
{
return {a,b};
}
并执行:
std::vector<A>, B
这样就解决了你的一个问题。上面需要修复以支持真正的输入迭代器特征,而不仅仅是上面与template<class A, class B>
auto cross_one_element( A& range_a, B& b_element ) {
auto a = range( std::begin(range_a), std::end(range_a) );
auto b = range( &b_element, (&b_element) +1 );
auto s = cross_iterator(a, b);
decltype(s) f{};
return cross_iterator(s, f);
}
一起使用的伪迭代器。
然后你必须编写一个带X矢量的代码,并将它转换为某个函数f的f(X)范围。
然后你必须编写一系列范围的代码,然后将它展平到一个范围内。
这些步骤中的每一步都不比上面更难。
有些图书馆会为您执行此操作。增强有一些,Rangesv3有一些,还有一堆其他范围操作库。
Boost甚至允许您通过指定for(:)
以及下一个*
上的操作来编写迭代器。当你的一个子向量为空时,做什么仍然很棘手,所以在这种情况下使用更通用的算法可能是明智的。
上面的代码未经过测试,而且是C ++ 14。 C ++ 11版本只是更冗长。