C++ 用于_each或累加以计算频率

C++ 用于_each或累加以计算频率,c++,c++11,C++,C++11,我一直在玩一个使用C++11和一些标准算法的简单示例,我不确定是使用std::acculate还是std::for_each。问题是要计算一个单词中的字母数,例如,输入“abracadabra”,你会得到 我的第一个缺点是使用std::acculate。这看起来很自然的原因是我们确实在积累一个值(一组频率)。此外,我最近一直在做一些函数式编程,acculate似乎是列表的自然翻译 这可能更容易编写和理解,我当然对它的效率感到高兴(尽管我怀念acculate的声明式、函数式风格) 在这样的例子中,

我一直在玩一个使用C++11和一些标准算法的简单示例,我不确定是使用
std::acculate
还是
std::for_each
。问题是要计算一个单词中的字母数,例如,输入“abracadabra”,你会得到

我的第一个缺点是使用
std::acculate
。这看起来很自然的原因是我们确实在积累一个值(一组频率)。此外,我最近一直在做一些函数式编程,
acculate
似乎是列表的自然翻译

这可能更容易编写和理解,我当然对它的效率感到高兴(尽管我怀念
acculate
的声明式、函数式风格)

在这样的例子中,有什么好的理由选择一个而不是另一个吗?从到目前为止的评论和回答来看,似乎如果我正在积累的值不是微不足道的,比如说一个
stl
容器而不是一个
int
,那么我应该总是更喜欢
,即使我真的在“积累”


为了完整起见,下面是编译和测试此代码的其余部分

#include <string>
#include <vector>
#include <numeric> // accumulate
#include <algorithm> // for_each 

using std::string;
using std::vector;

#include <iostream>

// ... insert code above ...

int main(int argc, char* argv[])
{
    const vector<int> charCounts = charsInWord("abracadabra");
    for(size_t c=0; c<charCounts.size(); ++c) {
        const int count = charCounts[c];
        if (count > 0) {
            std::cout << "'" << static_cast<char>(c) << "'" << " => " << count << "\n";
        }
    }
    return 0;
}
#包括
#包括
#包括//累积
#包括//
使用std::string;
使用std::vector;
#包括
// ... 在上面插入代码。。。
int main(int argc,char*argv[])
{
常量向量charCounts=charsInWord(“abracadabra”);
用于(尺寸c=0;c 0){

就我个人而言,我不会这样写:

vector<int> charsInWord(const string& text)
{
    std::vector<int> result(256); // One version never copied.

    int count = std::accumulate(text.begin(), text.end(), 0,
            [&result] (int count, char c)
         // ^^^^^^^^^ capture
            { 
                result[c]++;
                return count+1;
            } );
    // Might use count in the log file.
    return result;
}
在评论(以及一些删除的问题)中有一些关于使用std::map的讨论。在这里捕获并展开

我们可以使用
std::map
而不是
vector
。区别在于:

From:@Dave
std::map的查找时间为O(ln(n)),而vector为O(1)。因此需要考虑性能。还要注意的是,map的固定成本将高于vector。虽然这很小,但值得注意

From:@Dave
std::vector的固定大小约为256*4(1024),而map的大小约为12*个唯一字符(最小12个,最大3072个)。因此在现代机器中没有实际的空间考虑。但可能值得在手机等设备上进行优化

From:@POW
第三点是std::map使打印结果变得更加容易,因为您不需要检查空值

矢量打印

for(size_t c=0; c<charCounts.size(); ++c) {
    if (count > 0) {
        std::cout << "'" << static_cast<char>(c) << "' => " << charCounts[c] << "\n";
    }
}
(尺寸c=0;c 0)的
{

std::难道你的
累积
版本效率低下。我不知道你为什么希望应用移动语义,但它们没有。你将在每次迭代中创建一个新的向量。我不理解你对每个
都有
的问题;它实际上是相同的代码。@Dave谢谢,我至少认为值在e
return v2
可能会得到优化。我刚刚开始使用C++11,对其中的一些概念只有“外行”的看法。我需要做一些深入的工作。如果您没有看到右值参考(
&&
)或者
std::move
,没有移动语义。返回值可能在C++11之前已经过优化,因为在C++03中允许通过复制优化返回。无论如何,即使它确实移动了,也不是免费的。您最好像在另一个示例中那样做,在该示例中,您有一个更新的持久对象。@Dave:move-symantics kick再多一点,
rvalue引用
被移动。因此,函数返回值将被移动而不是复制。但在这种情况下,没有真正的区别。基于ftw的范围:
for(char c:text)++charCounts[c];
谢谢,当累积的和不是微不足道时,公平吗(例如,在本例中,是一个stl容器,而不是一个基本类型),您不会通过
acculate
的第三个参数来累加总和,而是像您在回答中所做的那样,通过一个副作用来更新总和(此评论反映了我对我的问题的编辑)@TooTone:又增加了一个选项。谢谢,这里的
for
循环比较合适,因为当使用整个范围时,每个
都比
好(我还有另一个例子,我只看了一个子范围)。
#include <string>
#include <vector>
#include <numeric> // accumulate
#include <algorithm> // for_each 

using std::string;
using std::vector;

#include <iostream>

// ... insert code above ...

int main(int argc, char* argv[])
{
    const vector<int> charCounts = charsInWord("abracadabra");
    for(size_t c=0; c<charCounts.size(); ++c) {
        const int count = charCounts[c];
        if (count > 0) {
            std::cout << "'" << static_cast<char>(c) << "'" << " => " << count << "\n";
        }
    }
    return 0;
}
vector<int> charsInWord(const string& text)
{
    std::vector<int> result(256); // One version never copied.

    int count = std::accumulate(text.begin(), text.end(), 0,
            [&result] (int count, char c)
         // ^^^^^^^^^ capture
            { 
                result[c]++;
                return count+1;
            } );
    // Might use count in the log file.
    return result;
}
vector<int> charsInWord2(const string& text)
{
    vector<int> result(256);
    std::for_each(text.begin(), text.end(),
        [&result] (char c)
        {
            result[c]++;
        } );
    return result;
}
vector<int> charsInWord2(const string& text)
{
    vector<int> result(256);
    for(char c : text) {result[c]++;}
    return result;
}
for(size_t c=0; c<charCounts.size(); ++c) {
    if (count > 0) {
        std::cout << "'" << static_cast<char>(c) << "' => " << charCounts[c] << "\n";
    }
}
for(auto loop: charCounts) {
    std::cout << "'" << loop.first << "' => " << loop.second << "\n";
}