简化FOR循环

时间:2009-09-09 12:04:43

标签: c++ functor simplify

我有一个基本上从双向量中读取值的函数,将它们附加到一个字符串(同时确保每个字符串之间的空间并设置它们的精度)并返回最终结果,减去最后的空格:

std::string MultiplePrintProperties::GetHpitchString()  
{    
    std::string str;  
    vector< double >::iterator it;    

    for ( it  = Vals.begin();    
          it != Vals.end();  
          it++ )  
    {
        ostringstream s;    

        // Set precision to 3 digits after the decimal point
        // and read into the string 
        boost::format fmt( "%.3f " ); 
        s << fmt % *( it );
        str.append( s.str() );      
    }

    // Remove last white space and return string   
    return str.substr( 0, str.length() - 1 ); 
}

我想知道这段代码是否可以以任何方式简化。我最近一直在调查for_each和functor的使用,但是我们无法弄清楚这些技术如何改进这个特定的例子。

7 个答案:

答案 0 :(得分:11)

由于您实际上是将双精度转换为字符串,并将这些字符串附加到字符串流中,因此您可以使用std::transform

// your functor, transforming a double into a string
struct transform_one_double {
   std::string operator()( const double& d ) const {
     boost::format fmt( "%.3f " ); 
     return (fmt % d).str();
   }
};

// iteration code, taking each value and inserting the transformed
// value into the stringstream.
std::transform( vals.begin(), vals.end()
              , std::ostream_iterator<std::string>( s, " ")
              , transform_one_double() );

答案 1 :(得分:4)

这些天似乎我有点老了。我会这样做的:

std::string MultiplePrintProperties::GetHpitchString()  
{    
    std::string str;  
    vector< double >::iterator it;    

    for ( it  = Vals.begin();    
          it != Vals.end();  
          it++ )  
    {
        // Set precision to 3 digits after the decimal point
        // and write it into the string 
        char buf[20];
        snprintf( buf, 20, "%.3f", *it );
        if (str.length() > 0)
            str.append(" ");
        str.append( buf );          
    }

    return str; 
}

答案 2 :(得分:2)

'fmt'变量应该在循环外声明,因为每次迭代设置格式都很慢而且不需要。也不需要stringstream。所以身体会变成这样的东西:

  std::string s;
  std::vector<double>::iterator i = vals.begin();

  if (i != vals.end())
{
  boost::format fmt("%.3f");
  s = str(fmt % *i++);

  while (i != vals.end())
    s += ' ' + str(fmt % *i++);
}

答案 3 :(得分:2)

我没有发现你的原始代码膨胀或迫切需要简化。然而,我会移动

boost::format fmt("%.3f");

ostringstream s;

离开循环以确保它们仅被初始化一次。这样可以节省很多str.append()。我猜xtofl的std :: transform()解决方案会有这个问题(虽然通过初始化一次为结构很容易修复)。

如果您正在寻找

的其他替代方案
 for (it = begin(); it != end(); ++it) {...}

签出BOOST_FOREACH,这将使您能够以下列方式进行迭代:

std::vector<double> list;
BOOST_FOREACH(double value, list) {
    ...
}

答案 4 :(得分:1)

您可以创建一个具有重载operator()的类,该类具有对std :: string的引用作为成员。您将声明此类的对象并将该字符串传递给构造函数,然后将该对象用作for_each的第三个参数。将为每个元素调用重载的operator(),并将文本附加到引用的字符串。

答案 5 :(得分:1)

如上所述,有很多方法可以实现这一目标,但...... 这种方法是不是只是想要一些更多的参数并被模板化? 假设你有

template< class tType >
std::string PrintVectorToArray( const std::vector< tType >& V, const char* Seperator );

然后你可以创建

  

1 2 3

     

1,2,3

     

1.0然后是2.0然后是5.0

任何可转换为字符串和任何分隔符的类型! 我曾经这样做过,现在发现自己经常使用这种方法。

答案 6 :(得分:0)

我建议使用单个字符串流和单一格式。那些并不便宜。

std::string MultiplePrintProperties::GetHpitchString()  
{    
    std::ostringstream s;    
    // Set precision to 3 digits after the decimal point
    static boost::format fmt( "%.3f " ); 

    for ( vector< double >::iterator it  = Vals.begin();    
          it != Vals.end(); it++ )  
    {
        // and read into the string 
        s << fmt % *( it );
    }
    // Remove last white space (if present) and return result
    std::string ret = s.str();
    if (!ret.empty()) ret.resize(ret.size()-1);
    return ret;
}

如果我有分析信息证明它仍然是瓶颈,我会考虑使用静态ostringstream:

static std::ostringstream s;    
...
std::string ret;
std::swap(ret, s.str());
return ret;