是否有标准算法复制到?

时间:2016-11-29 15:23:59

标签: c++ algorithm copy range standard-library

我正在使用istream_iterator<char> it,因此我不能反向迭代该范围(或迭代两次,没有大量的麻烦。)

我想复制,直到满足条件。在标准库中是否有类似的东西:

copy_until(it, istream_iterator<char>(), ostream_iterator<char>(cout), [](const unsigned char i){ return isalpha(i); })

如果我必须滚动一些东西,我只是希望能找到一些我无法弄清楚的魔法。

修改

我期望从我的copy_until函数中获得的行为是:

while(it != istream_iterator<char>()) {
    if(!isalpha(static_cast<unsigned char>(*it))) break;
    cout << *it++;
}

4 个答案:

答案 0 :(得分:3)

仅仅因为完整性,因为标准没有提供开箱即用的解决方案,这就是我的解决方案:

template<class _InIt, class _OutIt, class _Pr>
inline void copy_until (_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) {
  while ((_First != _Last) && _Pred(*_First)) {
    *_Dest++ = *_First++;
  }
}

这就是我使用它的方式:

copy_until(std::istreambuf_iterator<char>(is),
           std::istreambuf_iterator<char>(),
           std::ostreambuf_iterator<char>(os), 
           [] (char c) { return <some usefull condition here> });

例如,从输入流中读取仅包含alnum字符的字符串:

std::istream& operator>> (std::istream& is, std::string& n) {
  std::ostringstream str;
  copy_until(std::istreambuf_iterator<char>(is),
             std::istreambuf_iterator<char>(),
             std::ostreambuf_iterator<char>(str), 
             std::isalnum);
  n = str.str();
  return is;
}

答案 1 :(得分:2)

开箱即用之前没有副本。由于您是从istream复制的,因此没有其他选择,只能在其中使用带有break语句的循环。

答案 2 :(得分:0)

http://en.cppreference.com/w/cpp/algorithm提供对C ++中所有可用算法的非常有用的参考(不仅仅是算法库中的算法,还有 Numeric 内存 CStd库。)以下是复制算法,即将输入迭代器,输出迭代器和lambda作为参数:

  • copy_if“复制范围内的元素,由[firstlast定义... ...仅复制谓词pred返回true的元素”
  • transform“将给定的函数应用于范围并将结果存储在另一个范围内。”
  • remove_copy_if“将范围[firstlast)中的元素复制到从d_first开始的另一个范围,省略满足特定条件的元素”
  • replace_copy_if“将范围[firstlast)中的所有元素复制到以d_first开头的另一个范围,用{{1}替换满足特定条件的所有元素}“
  • unique_copy“将范围[new_valuefirst)中的元素复制到以last开头的另一个范围,使得没有连续的相等元素...使用给定的二元谓词d_first
  • 比较元素
  • partition_copy“将范围[pfirst)中的元素复制到两个不同的范围,具体取决于谓词last返回的值。满足谓词p,将复制到从p开始的范围。其余元素将复制到从d_first_true开始的范围“
  • merge 需要2 nd 输入范围
  • set_difference 需要2 nd 输入范围
  • set_intersection 需要2 nd 输入范围
  • set_symmetric_difference 需要2 nd 输入范围
  • set_union 需要2 nd 输入范围
  • adjacent_difference“计算范围[d_first_falsefirst)中每个相邻元素对的第二个和第一个之间的差异...使用给定的二进制值计算差异功能last
  • partial_sum“计算范围[opfirst)子范围内元素的部分总和,并将它们写入从last开始的范围。 。为了总结元素,第二个版本使用给定的二进制函数d_first。“
  • exclusive_scan“使用op为[binary_opfirst
  • 范围计算排他前缀和操作
  • inclusive_scan“使用last为[binary_opfirst
  • 范围计算包含前缀和操作
  • transform_exclusive_scan“使用last转换范围[firstlast)中的每个元素,然后使用unary_op计算一个独占前缀求和操作结果范围“
  • transform_inclusive_scan“使用binary_op转换范围[firstlast)中的每个元素,然后使用unary_op计算包含前缀和操作结果范围“

因为lambda仅用于修改范围[binary_opfirst)到last的1:1分配; d_firsttransform和所有数字库算法无用(replace_copy_ifadjacent_differencepartial_sum,{{1 }},exclusive_scaninclusive_scan。)

  • 如果满足lambda条件后,[transform_exclusive_scantransform_inclusive_scan)范围的其余部分将被直接复制到2 nd 输出迭代器, it可以解决您的问题
  • 如果满足lambda条件之后,[istream_iterator<char>()partition_copy)的余数将由函数迭代,则可以在每个值之后调用此函数。条件符合it(或istream_iterator<char>()copy_if
  • 但在一般情况下,您的问题的答案是标准算法不提供“copy_until”,因此您需要使用remove_copy_if - 循环

答案 3 :(得分:0)

copy_until可以通过std::find_ifstd::copy来实现。

使用与redleg相同的结构,该算法可以首先搜索终止符,然后复制范围。

template <class _InIt, class _OutIt, class _Pr>
inline void copy_until(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) {
    _InIt _posTerm = std::find_if(_First, _Last, _Pred);
    std::copy(_First, _posTerm, _Dest);
}

模板需要<algorithm><iterator>

以下是使用方法的示例:

std::vector<int> source = {1,2,3,4,5,6,7,8};
std::vector<int> dest {};

copy_until(source.begin(),source.end(), 
           back_inserter(dest),[](int c) {return c == 5;});

输出:

source: 1 2 3 4 5 6 7 8 
dest  : 1 2 3 4 

由于std::copy被定义为复制到最后,但是排除了[first,last)或其他术语,find_if的位置不会被复制。

如果您需要一个包含项,直到[first,last],我们需要做更多检查。如果终止符位于end(),则不应推进迭代器。

template <class _InIt, class _OutIt, class _Pr>
inline void copy_until(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred)
{
    _InIt _posTerm = std::find_if(_First, _Last, _Pred);
    if (_posTerm != _Last ) { _posTerm++; }
    std::copy(_First,_posTerm,_Dest);
}

前面的示例现在将输出:

source: 1 2 3 4 5 6 7 8 
dest  : 1 2 3 4 5