【问题标题】:Easiest way to combine 3 std::vector into a temporary single std::vector?将 3 个 std::vector 组合成一个临时的单个 std::vector 的最简单方法?
【发布时间】:2021-12-20 15:18:25
【问题描述】:

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


我有 三个 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)组合成一个临时的单个向量,这样我就可以只将一个向量传递给另一个类进行处理。

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

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

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

【问题讨论】:

  • 您提供的链接已经有了不错的答案。 std::copystd::back_inserter 似乎适合之前的 std::vector::reserve 如果你愿意的话。示例:std::copy(a.begin(),a.end(),std::back_inserter(combined);
  • 你说的是“搬家”,但搬家真的对你有用吗?还是您需要保留原始的 3 个单独的向量?如果您不关心保留 3 个原件,那么移动将是迄今为止最有效的方法。但是,什么都不做可能会更快。这意味着调整您尝试调用的算法,使其可以接受 3 个不同的迭代器对,而不是单个向量的单个对。
  • @CodyGray 我不想动。我声明我想保持原来的 3 不变。我正在尝试std::copy
  • @Staz 我确认使用std::copy 工作正常。谢谢。现在查看一些答案。
  • 里面有多少数据?请注意,std::vector 在调试模式下非常慢,在发布模式下非常快。我想知道缓慢的调试速度是否是这个问题的动机。

标签: c++ c++17 stdvector


【解决方案1】:

简单的复制分配有什么问题?

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

【讨论】:

  • 感谢您的建议。但这并没有考虑到一个或多个向量可能不存在。请注意,我必须先进行if 测试。
【解决方案2】:

您可以使用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

将排序范围 [first1,last1) 和 [first2,last2) 中的元素组合到一个从 result 开始的新范围中,其中所有元素都已排序。

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

将 [first,last) 范围内的元素复制到从 result 开始的范围内。.

所以这取决于你想要达到的目标。

【讨论】:

  • 谢谢,我确实有提升,所以我可以试试这个。但需要注意的是std::vector 可能不可用(由于find)。
  • 我认为您可以根据自己的条件单独调用联接
  • 我还添加了c++标准版,std::merge是一个选项但不仅你可以使用std::copy
  • 我用过std::copy。我想现在的问题是 - 使用 std::copy v std::merge 的优点/缺点是什么?
  • from cplusplus.com/reference/algorithm/merge/ std::merge : 将排序范围 [first1,last1) 和 [first2,last2) 中的元素组合到一个从 result 开始的新范围中,其中所有元素都已排序.std::copy将 [first,last) 范围内的元素复制到从 result 开始的范围内。。所以这取决于你想要实现什么。
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-15
    • 2020-12-20
    • 2017-08-22
    • 2014-12-12
    • 1970-01-01
    • 2019-11-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多