2016-02-09 7 views
20

ho vettore di vettori di T:Merge vettore di vettori in un unico vettore

std::vector<std::vector<T>> vector_of_vectors_of_T; 

voglio unire tutti in singolo vettore di T:

std::vector<T> vector_of_T; 

Attualmente sto usando questo metodo:

size_t total_size{ 0 }; 
for (auto const& items: vector_of_vectors_of_T){ 
    total_size += items.size(); 
} 
vector_of_T.reserve(total_size); 
for (auto const& items: vector_of_vectors_of_T){ 
    vector_of_T.insert(end(vector_of_T), begin(items), end(items)); 
} 

Esiste un metodo più semplice? Ti piace una funzione std pronta? In caso contrario, c'è un modo più efficiente di farlo manualmente?

+3

Penso che questa questione sarebbe una misura migliore per http://codereview.stackexchange.com/ – Default

+0

@Luca Pizzamiglio Grazie per correcing –

+0

@Default ho avuto un dubbio su questo prima di chiedere .. ma da quando sto chiedendo su un modo standard per farlo. potrebbe anche stare bene qui ... –

risposta

10

È un buon esercizio provare e scrivere un generico join. Il codice seguente prende un contenitore nidificato R1<R2<T> e restituisce un contenitore unito R1<T>. Si noti che a causa dei parametri di allocatore nella libreria standard, questo è un po 'macchinoso. Nessun tentativo è stato fatto per verificare la compatibilità allocatore ecc

Fortunatamente, c'è action::join funzione nella prossima libreria gamma-v3 da Eric Niebler, che è abbastanza robusta già e funziona oggi su Clang:

#include <range/v3/all.hpp> 
#include <algorithm> 
#include <iostream> 
#include <iterator> 
#include <numeric> 
#include <vector> 

// quick prototype 
template<template<class, class...> class R1, template<class, class...> class R2, class T, class... A1, class... A2> 
auto join(R1<R2<T, A2...>, A1...> const& outer) 
{ 
    R1<T, A2...> joined; 
    joined.reserve(std::accumulate(outer.begin(), outer.end(), std::size_t{}, [](auto size, auto const& inner) { 
     return size + inner.size(); 
    })); 
    for (auto const& inner : outer) 
     joined.insert(joined.end(), inner.begin(), inner.end()); 
    return joined; 
} 

int main() 
{ 
    std::vector<std::vector<int>> v = { { 1, 2 }, { 3, 4 } }; 

    // quick prototype 
    std::vector<int> w = join(v); 
    std::copy(w.begin(), w.end(), std::ostream_iterator<int>(std::cout, ",")); std::cout << "\n"; 

    // Eric Niebler's range-v3 
    std::vector<int> u = ranges::action::join(v); 
    std::copy(u.begin(), u.end(), std::ostream_iterator<int>(std::cout, ",")); std::cout << "\n"; 
} 

Live Example

+3

BTW, il termine matematico per tali "contenitori unibili" è [monad] (https://en.wikipedia.org/wiki/Monad_%28functional_programming%29).(Il concetto è piuttosto più generale di qualsiasi cosa tu possa scrivere con gli iteratori). – leftaroundabout

2

Suppongo che si possa provare std::merge/std::move utilizzato in un ciclo - che sono già esistenti algoritmi std. Non so se è più veloce.

8

Utilizzo di back_inserter e move;

size_t total_size{ 0 }; 
for (auto const& items: vector_of_vectors_of_T){ 
    total_size += items.size(); 
} 

vector_of_T.reserve(total_size); 
for (auto& items: vector_of_vectors_of_T){  
    std::move(items.begin(), items.end(), std::back_inserter(vector_of_T)); 
} 

Invece di copying, std::move dà un po 'di miglioramento delle prestazioni.

+4

senza benchmark e dal punto di vista astratto, dovrebbe essere più veloce del mio? e ha bisogno di prenotare anche prima? –

+0

@HubertApplebaum Vedo grazie –

+0

Questo potrebbe essere meno efficiente della versione di inserimento intervallo con gli iteratori di spostamento, specialmente per tipi di elementi banalmente copiabili (per i quali è probabile che l'inserto di intervallo sia fortemente ottimizzato). –