优雅的方式为矢量矢量提供flatting迭代器

时间:2016-10-25 15:29:15

标签: c++ c++11 vector c++14

我有一个适配器,其目标是为配对值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个迭代器:beginend,它在逻辑上与vector中的相同。

1 个答案:

答案 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版本只是更冗长。