2016-02-09 7 views
20

मैं टी की वैक्टर की वेक्टर है:मर्ज वेक्टर

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

मैं टी के एकल वेक्टर में उन सभी को मर्ज करना चाहते हैं:

std::vector<T> vector_of_T; 

मैं वर्तमान में उपयोग कर रहा हूँ यह विधि:

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

क्या कोई और सरल तरीका है? एक तैयार std समारोह की तरह? यदि नहीं, तो मैन्युअल रूप से ऐसा करने के लिए और अधिक प्रभावी तरीका है?

+3

मुझे लगता है कि इस प्रश्न के लिए – Default

+0

@Luca Pizzamiglio धन्यवाद एक बेहतर फिट होगा .. लेकिन जब से मैं के बारे में पूछ रहा हूँ ऐसा करने का एक कठोर तरीका। यह यहां भी फिट हो सकता है ... –

+0

correcing @Default मैं पूछ रहा से पहले इस बारे में संदेह नहीं था के लिए http://codereview.stackexchange.com/ –

उत्तर

10

यह सामान्य join को आजमाने और लिखने का एक अच्छा अभ्यास है। नीचे दिया गया कोड एक नेस्टेड कंटेनर R1<R2<T> लेता है और एक कंटेनर R1<T> लौटाता है। ध्यान दें कि मानक लाइब्रेरी में आवंटन पैरामीटर की वजह से, यह थोड़ा बोझिल है। कोई प्रयास नहीं संभाजक अनुकूलता आदि

सौभाग्य से, वहाँ एरिक Niebler द्वारा आगामी रेंज-v3 पुस्तकालय में action::join समारोह के लिए जाँच करने के लिए किया जा रहा है, कि काफी पहले से ही मजबूत है और बजना पर आज काम करता है:

#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

बीटीडब्ल्यू, ऐसे "जुड़ने योग्य कंटेनर" के लिए गणितीय शब्द [monad] है (https://en.wikipedia.org/wiki/Monad_%28functional_programming%29)।(अवधारणा इसके अलावा कुछ भी सामान्य से अधिक सामान्य है जो आप लिख सकते हैं।) – leftaroundabout

2

मुझे लगता है कि आप std::merge/std::move को एक लूप में उपयोग करने का प्रयास कर सकते हैं - जो पहले से मौजूद स्टडी एल्गोरिदम हैं। पता नहीं है कि यह तेज़ है या नहीं।

8

back_inserter और 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)); 
} 

के बजाय copying, std::move यह थोड़ा प्रदर्शन को बढ़ाने देता है।

+4

, क्या यह तेज़ होना चाहिए? और क्या इससे पहले भी इसे आरक्षित की जरूरत है? –

+0

@ हबर्ट एप्पलबाम मुझे धन्यवाद –

+0

यह इटेटरेटर को स्थानांतरित करने के साथ रेंज डालने वाले संस्करण की तुलना में कम कुशल हो सकता है, खासतौर पर छोटे-छोटे कॉपी करने योग्य तत्व प्रकारों के लिए (जिसके लिए रेंज सम्मिलन को अत्यधिक अनुकूलित किया जा सकता है)। –