【问题标题】:Convenient way to return filtered collection返回过滤集合的便捷方式
【发布时间】:2016-05-14 16:10:08
【问题描述】:

问题

假设我有两个 Iterator 类型的迭代器 beginend 和一些谓词 predicate(存储在 obj 中)。我想实现我可以写的方法some_collection()o

for(auto element: obj.get_collection()) {
    do_smth()
}

所以它只适用于满足谓词的元素(即等同于这样的smth)

for (auto element: range(begin, end)) {
    if (predicate(element)) {
        do_smth();
    }
}

我的解决方案

我想到的大致实现如下(伪代码):

struct Wrapper {
    op++() {
        do {
           ++value;
        while (!predicate(*value));
    }
    op*() {
        return *value;
    }
    op !=(Iterator other) {
        return value != other.value;
    }
    Iterator value;
}

返回对象的begin() 会是这样的

value = begin;
while (!predicate(*value)) ++value;
return Wrapper(value)

end() 就是Wrapper(end)

注意事项

我不喜欢这个实现:

  • 冗长:我只需要过滤,并且必须编写大量代码
  • 初始化有点丑 - 必须在那里增加
  • 如果我不迭代所有对象(将破坏或不使用任何值),我将额外迭代(到下一个未使用的元素)

我可以在每次取消引用之前进行迭代(以修复第 2 点和第 3 点),但这会使!= end 检查更加困难(我需要提前减少 end 或在检查本身中使用增量,这意味着在循环)

要求

我没有特定的语言版本要求,甚至对使用尚未批准的实现感兴趣。但 C++11 会是最棒的

我对支持的迭代器类别没有具体要求。我相信我的会与ForwardIterators 合作。

我对代码的可理解性和效率都很感兴趣。

任何更接近银弹的解决方案? :)

【问题讨论】:

  • 如果您不想预先计算过滤范围(想到std::partition()),您的代码似乎足够接近最优。虽然如果你已经担心这个级别的性能......

标签: c++ iterator iteration filtering


【解决方案1】:

您可以使用BOOST filter_iterator。以下是链接页面中的示例:

struct is_positive_number {                                                                         
  bool operator()(int x) { return 0 < x; }                                                          
  };                                                                                                

int main()                                                                                          
{                                                                                                   
  int numbers_[] = { 0, -1, 4, -3, 5, 8, -2 };                                                      
    const int N = sizeof(numbers_)/sizeof(int);                                                     

  typedef int* base_iterator;                                                                       
    base_iterator numbers(numbers_);                                                                

  // Example using filter_iterator                                                                  
    typedef boost::filter_iterator<is_positive_number, base_iterator>                               
        FilterIter;                                                                                 

  is_positive_number predicate;                                                                     
    FilterIter filter_iter_first(predicate, numbers, numbers + N);                                  
      FilterIter filter_iter_last(predicate, numbers + N, numbers + N);                             

  std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator<int>(std::cout, " "));       
    std::cout << std::endl;                                                                         

  // Example using make_filter_iterator()                                                           
    std::copy(boost::make_filter_iterator<is_positive_number>(numbers, numbers + N),                
                boost::make_filter_iterator<is_positive_number>(numbers + N, numbers + N),          
                        std::ostream_iterator<int>(std::cout, " "));                                
                          std::cout << std::endl;                                                   

  // Another example using make_filter_iterator()                                                   
    std::copy(                                                                                      
          boost::make_filter_iterator(                                                              
                std::bind2nd(std::greater<int>(), -2)                                               
                        , numbers, numbers + N)                                                     

    , boost::make_filter_iterator(                                                                  
              std::bind2nd(std::greater<int>(), -2)                                                 
                  , numbers + N, numbers + N)                                                       

    , std::ostream_iterator<int>(std::cout, " ")                                                    
      );                                                                                            

  std::cout << std::endl;                                                                           

  return boost::exit_success;                                                                       
}                                                                                                   

【讨论】:

  • 谢谢,我检查了他们的实现,和我的基本一样
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-12
  • 1970-01-01
  • 2010-09-08
  • 1970-01-01
  • 2021-08-02
  • 2013-04-27
  • 1970-01-01
相关资源
最近更新 更多