2016-10-25 2 views
3

Ich habe einen Adapter, dessen Ziel ist, Forward-Iterator für Paar Werte pair<FeatureVector, Label> bereitzustellen. In meiner internen Darstellung speichere ich Daten wie vector<pair<vector<strings>, Label>>.Elegante Möglichkeit, Flattern Iterator für Vektor von Vektoren

So während Iterationen, muss ich es glätten und jedes einzelne string, wandeln die kurzen Satz wie ist „heute Öltropfen massiv“, zu FeatureVector

In rohen Variante Ich habe so etwas wie:

{ 
    {"Oil drops massively","OPEC surge oil produciton","Brent price goes up" -> "OIL_LABEL"}, 
    {"France consume more vine", "vine production in Italy drops" -> "VINE_LABEL"} 
} 

und ich muss wandeln es in:

{ 
    vectorize("Oil drops massively") -> "OIL_LABEL", 
    vectorize("OPEC surge oil produciton") -> "OIL_LABEL", ... , 
    vectorize("vine production in Italy drops") -> "VINE_LABEL" 
} 

vectorize() -> es ist eine Umwandlung von Satz spärlich Vektor so "Oil drops on NYSE" -> {0,1,0..0,1,0..0,1}

Der einfachste Weg wird sein, neue Vektor zu erstellen und es mit allen Daten zu initialisieren und dann Iteratoren zu verwenden, aber das ist ziemlich Ressource havy Betrieb, also idealerweise möchte ich diese Art der Konvertierung über jeden erfolgen Iteration. Was ist der eleganteste Weg für eine solche Umwandlung?

Dies ist eine vereinfachte Version der Datenstruktur zum Speichern von Textkorpus. Iteratoren müssen später bei der Klassifizierer-Initialisierung verwendet werden, die 2 Iteratoren benötigen: begin und end, die logisch der gleichen ist wie in vector.

+0

Wie genau müssen Sie iterieren?'for (:)' Schleife nur eine nach der anderen? – Yakk

+1

Sie müssen jede 'string' im' vector' in einen 'FeatureVector' umwandeln oder Sie müssen den' vector ' in einen 'FeatureVector' konvertieren? – NathanOliver

+0

Was ist 'FeatureVector'? Sie müssen was in was platt machen? – Barry

Antwort

1

Ein einfacher Bereichstyp:

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}; 
} 

Hier ist ein nicht-konformer Pseudo-Iterator, der das Kreuzprodukt von zwei ranes tut:

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}; 
} 

Daraus Sie std::vector<A>, B zu nehmen und zu tun:

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); 
} 

Das löst also eines Ihrer Probleme. Das obige muss behoben werden, um echte Eingabe-Iterator-Funktionen zu unterstützen, nicht nur den obigen Pseudo-Iterator, der mit for(:) arbeitet.

Dann müssen Sie Code schreiben, der einen Vektor von X nimmt und ihn für eine Funktion f in einen Bereich von f (X) transformiert.

Dann müssen Sie Code schreiben, der eine Reihe von Bereichen verwendet, und flacht ihn in einen Bereich ab.

Jeder dieser Schritte ist nicht schwieriger als oben.

Es gibt Bibliotheken, die das für Sie tun. Boost hat einige, Rangesv3 hat einige, ebenso wie ein Haufen anderer Range-Manipulation-Bibliotheken.

Boost sogar können Sie einen Iterator schreiben, indem Sie angeben, was zu tun ist * und auf nächste und ==. Was zu tun ist, wenn einer Ihrer Untervektoren leer ist, bleibt schwierig, daher ist es in diesem Fall ratsam, allgemeinere Algorithmen zu verwenden.

Der obige Code wurde nicht getestet und ist C++ 14. C++ 11-Versionen sind lediglich ausführlicher.

Verwandte Themen