2015-02-16 2 views
2

Существует вопрос о том, как объединить два вектора: Concatenating two std::vectors. Тем не менее, я счел целесообразным начать новую, так как мой вопрос немного более конкретно ....Как объединить многие std :: векторы?

У меня есть два класса, которые выглядят следующим образом:

class AClass { 
public: 
    std::vector<double> getCoeffs() {return coeffs;} 
private: 
    std::vector<double> coeffs; 
}; 

class BClass { 
public: 
    std::vector<double> getCoeffs() {return ...;} 
private: 
    std::vector<AClass> aVector; 
}; 

Что является лучшим способом (т.е. избегать ненужного копирования и т. д.), чтобы объединить коэффициенты от каждого элемента в aVector?

Моя самая первая попытка была

std::vector<double> BClass::getCoeffs(){ 
    std::vector<double> coeffs; 
    std::vector<double> fcoefs; 
    for (int i=0;i<aVector.size();i++){ 
     fcoefs = aVector[i].getCoeffs(); 
     for (int j=0;j<fcoefs.size();j++{ 
      coeffs.push_back(fcoefs[j]); 
     }   
    } 
    return coeffs; 
} 

Я уже знаю, как избежать внутренней цикл (благодаря вышеупомянутой должности), но я уверен, что, что с помощью некоторого станд алгоритма этой может выполняться в одной строке.

Я не могу использовать C++ 11 на данный момент. Тем не менее, мне также будет интересно, как это сделать на C++ 11 (если есть преимущество перед «no C++ 11»).

EDIT: Я попытаюсь немного перефразировать вопрос, чтобы сделать его более понятным. Конкатенация двух векторов может быть выполнена через вставку. Для моего примера я бы использовал это:

std::vector<double> BClass::getCoeffs(){ 
    std::vector<double> coeffs; 
    std::vector<double> fcoefs; 
    for (int i=0;i<aVector.size();i++){ 
     fcoefs = aVector[i].getCoeffs(); 
     coeffs.insert(coeffs.end(),fcoefs.begin(),fcoefs.end());   
    } 
    return coeffs; 
} 

Можно ли избежать цикла for? я мог себе представить, что можно написать что-то вроде

for_each(aVector.begin(),aVector.end(),coeffs.insert(coeffs.end(),....); 
+0

это помогает: http: //stackoverflow.com/questions/3177241/best-way-to-concatenate-two-vectors –

+2

См. Это [ответ Ben Voigt] (https://stackoverflow.com/questions/ 17636690/хороший-путь к Append-а-вектор-к-себе). –

+0

@MohitBhasi - это дубликат другого вопроса, на который я ссылался. Возможно, я должен изменить заголовок на «Как объединить MANY std :: vectors»;) – user463035818

ответ

1

Вы можете сделать это в C++ 11:

std::for_each(aVector.begin(), aVector.end(), [&](AClass i){const auto& temp = i.getCoeffs(); coeffs.insert(coeffs.end(), temp.begin(), temp.end());}); 

C++ 03 является более трудным, потому что ему не хватает лямбды и bind.

О, как хорошо, как вы можете сделать, это использовать копию во внутреннем цикле:

for(std::vector<AClass>::iterator it = aVector.begin(); it != aVector.end(); ++it){ 
    const std::vector<double>& temp = it->getCoeffs(); 
    coeffs.insert(coeffs.end(), temp.begin(), temp.end()); 
} 

Они оба по существу то же самое, если бы вы могли улучшить свое время работы на обоих, возвращая const std::vector<double>& из getCoeffs.

EDIT:

Arg, просто видел, как вы добавили insert к вашему вопросу. Я думал, что действительно буду помогать тебе там. В качестве утешительного наконечника то, о чем вы действительно спрашиваете, - это сглаживание std::vectorstd::vectors. У этого есть ответ here. Но если у вас есть доступ к повышению, вы должны посмотреть: http://www.boost.org/doc/libs/1_57_0/libs/multi_array/doc/reference.html#synopsis

+0

@ T.C. Спасибо, сэр, попытался скопировать это вручную и слишком взволнован точкой с запятой. –

0

Первый шаг - избежать лишних выплат. Если вы знаете, что не будете увеличивать возвращаемое значение, вы можете зарезервировать его точно в нужном размере.

std::vector<double> BClass::getCoeffs(){ 
    typedef std::vector<double> dvec; 
    dvec coeffs; 
    typedef std::vector<AClass> avec; 
    typedef std::vector<dvec> ddvec; 
    ddvec swap_space; 
    swap_space.reserve(aVector.size()); 
    size_t capacity = 0; 
    for (avec::const_iterator it = aVector.begin(); it != aVector.end(); ++it) { 
    dvec v = it->getCoeffs(); // RVO elision! 
    capacity += v.size(); 
    swap_space.push_back(); 
    v.swap(swap_space.back()); 
    } 
    dvec retval; 
    retval.reserve(capacity); 
    for (ddvec::iterator it = swap_space.begin(); it != swap_space.end(); ++it) { 
    retval.insert(retval.end(), it->begin(), it->end()); 
    } 
    return retval; // NRVO 
} 

это следует избегать более одного распределения за AClass (как принудительный их API! Вы должны иметь vector<?> const& аксессор), плюс один выделения для возвращаемого значения.

Рекомендуется установить фиксатор AClass.

+0

извините, но без дальнейших объяснений я не понимаю, почему это должно быть так сложно. Кстати, «AClass :: coeffs» имеют фиксированный размер. Хотелось бы использовать std :: array, но я не могу использовать C++ 11. – user463035818

+0

@ tobi303 хорошо, каждый получает выделение буфера. Поэтому, если я его дважды назову, я выделяю дважды. Но я также хочу, чтобы размер объединенного буфера, прежде чем я начал добавлять, поэтому мне нужно хранить каждый дополнительный буфер, пока я суммирую их длину, а затем добавляю их в цель. Более простое решение - получить, добавить, повторить, а не повторять повтор повторного добавления - делает O (lg (n)) больше распределений (n - общее количество элементов). Выше всего это не стоит, но он говорит мне, что ваш интерфейс, который копирует буфер, должен быть улучшен * если * это узкое место производительности. – Yakk

+0

большое спасибо. Мне нужно взглянуть глубже, чтобы действительно понять, что происходит, и что будет лучшим решением для моего приложения. – user463035818