【问题标题】:How to take certain elements from one container and insert a transform of those into another container?如何从一个容器中获取某些元素并将这些元素的转换插入另一个容器?
【发布时间】:2023-04-03 16:57:01
【问题描述】:

我有一个vector<int*>,我想将所有指向的元素放入vector<int>。所有未指向的元素都设置为nullptr

我正在考虑做这样的事情:

vector<int> copy_valid_elements(vector<int*> piv)
{
 vector<int> result;
 result.reserve(piv.size());
 auto end_it = std::remove_if(piv.begin(), piv.end(), [](int* p) { return !p; });
 std::transform(piv.begin(), end_it, back_inserter(result), [](int* p) { return *p; });
 return result;
}

但这需要不必要地移动数组中的元素。我可以做一个 for 循环,但我希望有一个算法是 std::copy_ifstd::transform 之间的交叉。有这样的野兽吗?

【问题讨论】:

  • 为什么会有一个指针的向量?它们是指向 single 值的指针,还是指向动态分配的数组的指针?如果是第一个,为什么要指针?如果是后者,为什么不是向量的向量?
  • 标准库并非旨在包含所有可能的算法,而是一组核心示例 - 我之前已经编写了transform_if,这很容易。遗憾的是,目前的模型并不容易支持组合算法——建议的范围库在某种程度上可以帮助解决这个问题。您也可以考虑将boost::filter_iterator 输入std::transform
  • 如果你不需要使用algorithm,它只是for(...){if(...)push_back(...)}
  • @appleapple 重点不是说这是一个特别难解决的问题,而是很容易不优雅地解决 - 使用命名且易于理解的算法比for 循环更清楚地表达意图,并且不太可能在以后进行调整/添加,从而使行为略有不同,因此不太清楚。
  • @BoBTFish 我个人觉得algorithm 很混乱。如果它可以像LINQ 那样简单易用,我可能会改变主意。但就像现在一样,普通的range based for(可能在具有正确名称的函数中)对我来说非常清晰和灵活。

标签: c++ stl-algorithm


【解决方案1】:

这是一个应用可选转换的函数模板,带有两个谓词:一个用于过滤,一个用于实际映射。

template <class InpIt, class OutIt, class Pred, class Fct>
OutIt transform_if(InpIt first, InpIt last, OutIt dest, Pred pred, Fct transform)
{
   while (first != last) {
      if (pred(*first))
         *dest++ = transform(*first);

      ++first;
   }

   return dest;
}

你可以这样称呼它

int n1 = 1, n2 = 2, n3 = 3;

std::vector<int*> input{&n1, nullptr, nullptr, nullptr, &n2, &n3, nullptr};
std::vector<int> result;

transform_if(input.cbegin(), input.cend(), std::back_inserter(result),
    [](auto *i){ return i != nullptr; }, [](auto *i){ return *i; });

另一种可能性是使用范围库,因为它们的主要目的之一是轻松组合算法。带升压范围:

#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>

using namespace boost::adaptors;

/* Variable setup as above... */

boost::copy(input | filtered([](auto *i){ return i != nullptr; }) | indirected,
    std::back_inserter(result));

【讨论】:

  • 您需要在写入时取消引用dest 迭代器。
  • @BoBTFish 谢谢,已修复。
  • 感谢您编写算法,但我的问题不是创建一个新算法,而是查看是否已经存在一个算法。 boost 很有趣,我会研究一下,但不幸的是,对于我试图解决的问题,我无法使用 boost。再次感谢。
  • (Meta-answer):您应该能够轻松编写自己的算法。标准库中的那些并没有什么神奇之处。他们只是比其他人得到更多的“关注”。编写自己的算法不是火箭科学。 @lubgr 为您写的那个完全符合您的要求,并且做得很好。我能看到的唯一改进是它最后需要一个return dest; 来返回(修改后的)输出迭代器。
  • @MarshallClow 感谢您的提示!我调整了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-15
相关资源
最近更新 更多