简化嵌套的STL容器遍历

时间:2012-06-06 16:15:26

标签: c++ stl

我有一个包含涉及STL容器的嵌套遍历的代码。特别是我有一个顶级容器(列表),其中包含子列表,这些子列表包含更多子列表。对于例如在DICOM结构中,患者可以进行多项研究,每项研究可以有多个系列。我必须对Series对象执行一些操作,并且到达它们的唯一方法是深入循环,如下所示。

伪代码看起来像这样。

STLContainer top;
STLContainer::iterator top_iter;

for ( top_iter= top.begin(); top_iter != top.end(); ++top_iter) {
 STLContainer mid = *top_iter;
 STLContainer::iterator mid_iter;

 for ( mid_iter = mid.begin(); mid_iter!= mid.end(); ++mid_iter) {
  STLContainer bottom = *mid_iter;
  STLContainer::iterator bottom_iter;

  for(bottom_iter = bottom.begin(); bottom_iter != bottom.end(); ++bottom_iter){
     ExecuteSomething(*bottom_iter); // Finally do something with the stored object
  }
 }

}

现在如果我必须在这些“底部”对象上重复执行一系列操作,我必须一次又一次地进行遍历。如果我想使用STL算法,我需要为每个嵌套级别写入至少3行“for_each”。

是否有人知道缩短此代码的技术可能会有点像这样?

// Drills down to the deepest nested container
for_each(top.begin(), top.end(), DrillDownAndExecuteOnBottom());

只能在一行中使用?像这样的东西? 谢谢!

3 个答案:

答案 0 :(得分:3)

假设容器不是所有相同的元素类型:

struct DrillDownAndExecuteOnBottom
{
  template<typename T>
    void operator()(T& t) const
    { for_each(t.begin(), t.end(), *this); }

  void operator()(Bottom& b) const
  { ExecuteSomething(b); }
};

这将进行深度优先遍历,直到它到达Bottom个对象。

答案 1 :(得分:1)

您可以编写遍历一次并使用lambdas封装它。

void for_each_bottom( Top &top, const std::function<void(Bottom &)> &fn ) {  
    for (auto t = top.begin(); t != top.end(); ++t)  
        for (auto m = t->begin(); m != t->end(); ++m)  
            for (auto b = m->begin(); b != b->end(); ++b)  
                 fn( *b );

}  

void demo( Top &top ) {
    for_each_bottom( top, []( Bottom &bottom ) {
        ExecuteSomething( bottom );
    } );
}

(如果您愿意,可以使用Jonathan Wakely的递归/模板方法进行遍历;这些嵌套循环很简单但不太通用。如果您愿意,也可以使用模板类型而不是std :: function&lt;&gt;。我通常除非需要,否则我们更愿意避开模板。)

答案 2 :(得分:0)

这里有一些递归函数的半伪代码应该可以解决这个问题:

void iterate(Container c)
{
    for (Iterator iter = c.begin(); iter != c.end(); iter++)
    {
        if (*iter is a Container)  // I forget how to do type-checking in C++
            iterate(*iter);
        else
            ExecuteSomething(*iter);
    }
}

编辑:

这样的东西可能更灵活(不记得C ++是否处理与C /不同的函数指针/有更好的方法来利用它们,但无论如何)

void recursiveIterateAndExecute(Container c, void func(Container))
{
    for (Iterator iter = c.begin(); iter != c.end(); iter++)
    {
        if (*iter is a Container)  // I forget how to do type-checking in C++
            recursiveIterateAndExecute(*iter, func);
        else
            func(*iter);
    }
}

有可能修改这些方法更符合STL算法,但由于我没有用C ++做很多工作,所以我无法对此做出真正的评论。