简化 FOR 循环

发布于 2024-08-03 19:56:33 字数 748 浏览 9 评论 0原文

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

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 和函子的使用,但无法弄清楚这些技术如何改进这个特定的示例。

I have a function that essentially reads values in from a vector of doubles, appends these to a string (while ensuring a space between each and setting their precisions) and returns the end result, minus the final whitespace:

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 ); 
}

I would like to find out if this code could be simplified in any way. I have recently been investigating the use of for_each and functors in particular but have not been able to figure out how these techniques could improve this particular example.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

り繁华旳梦境 2024-08-10 19:56:33

由于您实际上是将双精度数转换为字符串,并将这些字符串附加到字符串流中,因此您可以使用 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() );

Since you're actually transforming doubles into strings, and appending these strings to a stringstream, you can use std::transform for that:

// 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() );
橙幽之幻 2024-08-10 19:56:33

看来我这些天有点老了。我会这样做:

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; 
}

Seems like I'm a bit old skool these days. I would have done this:

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; 
}
那支青花 2024-08-10 19:56:33

'fmt' 变量应该在循环之外声明,因为每次迭代设置格式都很慢并且不需要。也不需要字符串流。那么身体就会变成这样:

  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++);
}

The 'fmt' variable should be declared outside your loop, as setting the formatting up every iteration is slow and not needed. also the stringstream is not needed. So the body would become something like this:

  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++);
}
半山落雨半山空 2024-08-10 19:56:33

我没有发现您的原始代码臃肿或迫切需要简化。然而,我会将

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) {
    ...
}

I did not find your original code bloated or in desperate need of simplification. I would however move the

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

and

ostringstream s;

out of the loop to ensure they are only initialized once. This would save of a lot of str.append()-ing too. I'm guessing xtofl's std::transform() solution will have this problem (it's easy to fix by initializing it once for the struct though).

If you are looking for other alternatives to

 for (it = begin(); it != end(); ++it) {...}

check out BOOST_FOREACH which would enable you to iterate in the following manner:

std::vector<double> list;
BOOST_FOREACH(double value, list) {
    ...
}
影子是时光的心 2024-08-10 19:56:33

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

You can create a class with an overloaded operator() having a reference to std::string as a member. You will declare an object of this class and pass the string into constructor, then use the object as the third parameter to for_each. Overloaded operator() will be invoked for each element and append the text to the referenced string.

风吹雪碎 2024-08-10 19:56:33

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

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

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

as stated above, lots of ways to achive this, but...
doesn't this method just beg for having some more parameters and being templatized?
suppose you had

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

then you could create

1 2 3

1, 2, 3

1.0 and then 2.0 and then 5.0

for any type convertable to string and with any seperator!
I once did it this way, and now find myself using this method a lot.

一笔一画续写前缘 2024-08-10 19:56:33

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

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;

I'd suggest to use a single stringstream and a single format. Those aren't exactly cheap.

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;
}

If I had profiling information proving it was still a bottleneck, I'd consider using a static ostringstream:

static std::ostringstream s;    
...
std::string ret;
std::swap(ret, s.str());
return ret;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文