将 3 std::vector 组合成临时单个 std::vector 的最简单方法?

Easiest way to combine 3 std::vector into a temporary single std::vector?

我看过这个讨论(Concatenating two std::vectors),但它涉及组合(如移动)两个std::vector数组。


我有 three std::vectors 我正在使用 C++17:

  1. m_mapHist[m_eHistAssign][strName]
  2. m_mapScheduleHist[m_eHistAssign][strName]
  3. m_mapScheduleFutureHist[m_eHistAssign][strName]

每个向量的类型都是 std::vector<COleDateTime>。我不想改变这些向量。相反,我想将它们组合(copy 我猜)到一个临时的单个向量中,这样我就可以将一个向量传递给另一个 class 进行处理。

目前我正在通过迭代手动执行此操作:

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

有没有更简单的方法来创建这个临时向量?

您可以使用 boost::join。示例:

std::vector<COleDateTime> v1;
std::vector<COleDateTime> v2;
std::vector<COleDateTime> v3;
std::vector<COleDateTime> result;

result = boost::join(boost::join(v1, v2), v3);

自 c++17 起,标准也有一个 std::merge util 函数:

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

std::mergestd::copy

之间的区别

来自 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.

来自 cplusplus.com/reference/algorithm/copy/ std::copy:

Copies the elements in the range [first,last) into the range beginning at result..

所以这取决于你想要达到什么。

使用标准库,您可以做到这一点。顺便说一句,我还没有测试代码。它可能包含错误。

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

简单的复制赋值有什么问题?

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

由于您的输入向量可能不存在,这里有一个版本可以解决这个问题:

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