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