I have seen this discussion (Concatenating two std::vectors) but it concerns combining (as in moving) two std::vector
arrays.
I have three std::vectors
and I am using C 17:
m_mapHist[m_eHistAssign][strName]
m_mapScheduleHist[m_eHistAssign][strName]
m_mapScheduleFutureHist[m_eHistAssign][strName]
Each vector is of type std::vector<COleDateTime>
. I don't want to change these vectors. Instead, I want to combine them (copy I guess) into a temporary single vector, so I can pass just the one vector to another class for processing.
At the moment I am doing this manually through iteration:
std::vector<COleDateTime> vecAssignmentDate;
// Past items from the history database
if (m_mapHist[m_eHistAssign].find(strName) != m_mapHist[m_eHistAssign].end())
{
for (const auto& historyItemDate : m_mapHist[m_eHistAssign][strName])
{
vecAssignmentDate.push_back(historyItemDate);
}
}
// Past items on the active schedule
if (m_mapScheduleHist[m_eHistAssign].find(strName) != m_mapScheduleHist[m_eHistAssign].end())
{
for (const auto& historyItemDate : m_mapScheduleHist[m_eHistAssign][strName])
{
vecAssignmentDate.push_back(historyItemDate);
}
}
// Future items (both on the active schedule and in the history database)
if (m_mapScheduleFutureHist[m_eHistAssign].find(strName) != m_mapScheduleFutureHist[m_eHistAssign].end())
{
for(const auto &historyItemDate : m_mapScheduleFutureHist[m_eHistAssign][strName])
{
vecAssignmentDate.push_back(historyItemDate);
}
}
Is there an easier way to create this temporary vector?
CodePudding user response:
You may use boost::join
. Example:
std::vector<COleDateTime> v1;
std::vector<COleDateTime> v2;
std::vector<COleDateTime> v3;
std::vector<COleDateTime> result;
result = boost::join(boost::join(v1, v2), v3);
Since c 17 the standard also have a std::merge
util function:
std::vector<COleDateTime> v1;
std::vector<COleDateTime> v2;
std::vector<COleDateTime> v3;
std::vector<COleDateTime> result;
std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(result));
std::merge(v3.begin(), v3.end(), result.begin(), result.end(), std::back_inserter(result));
Differences between std::merge
and std::copy
from cplusplus.com/reference/algorithm/merge/ std::merge
:
Combines the elements in the sorted ranges [first1,last1) and [first2,last2), into a new range beginning at result with all its elements sorted.
from cplusplus.com/reference/algorithm/copy/ std::copy
:
Copies the elements in the range [first,last) into the range beginning at result..
So it depends on what you want to achieve.
CodePudding user response:
Using a standard library, you can do this. BTW, I have not tested the code. It could contain errors.
#include <algorithm>
template<typename T, typename U, typename ...Args>
std::vector<COleDateTime> combine(T key1, U key2, Args ...arg) {
std::vector<COleDateTime> ret;
for (const auto& v : {arg...}) {
if (v[key1].find(key2) != v[key1].cend()) {
std::copy(v[key1][key2].begin(), v[key1][key2].end(), std::back_inserter(ret));
}
}
return ret;
}
CodePudding user response:
What's wrong with a simple copy assignment?
const std::vector<COleDateTime>& v1;
const std::vector<COleDateTime>& v2;
const std::vector<COleDateTime>& v3;
std::vector<COleDateTime> result;
result.reserve(v1.size() v2.size() v3.size());
for(const std::vector<COleDateTime>* vec: {&v1, &v2, &v3})
result.insert(result.end(), vec->begin(), vec->end());
Since your input vectors may not exist, here is a version that accounts for this:
using vector_type = std::vector<COleDateTime>;
using map_type = std::map<std::string, vector_type>;
auto find_or_null = [](const map_type& map, const std::string& key) noexcept
-> const vector_type* {
map_type::const_iterator found = map.find(key);
return found == map.end() ? nullptr : &found->second;
};
const auto vecs = { find_or_null(n_mapHist, strName),
find_or_null(m_mapScheduleHist, strName),
find_or_null(m_mapScheduleFutureHist, strName)
};
std::size_t size = 0;
for(const vector_type* vec: vecs)
if(vec)
size = vec->size();
vector_type result;
result.reserve(size);
for(const vector_type* vec: vecs)
if(vec)
result.insert(result.end(), vec->begin(), vec->end());