1

作为更大程序的一部分,我正在尝试获取向量中所有相同字符串的数量的输出。经过大量研究,我设法将一些可行的东西放在一起,但看起来很混乱,我想知道是否有更好的方法来做到这一点。

#include <vector>
#include <string>
#include <map>
#include <algorithm>
#include <iostream>

using namespace std;

void setMap(string i);
void addMap(string i);
map<string, int> myMap;

int main()
{
    vector<string> myVector;
    string myArray[6]={"foo","foo","bar","roo","foo","bar"};
    for (int i=0; i<6; i++)
    {
        myVector.push_back(myArray[i]);
    }
    for_each (myVector.begin(), myVector.end(), setMap);
    for_each (myVector.begin(), myVector.end(), addMap);
    for (map<string, int, less< string >>::const_iterator iter = myMap.begin();
      iter != myMap.end(); ++iter )
      cout <<iter->first<<'\t'<<iter->second<<endl;
    return 0;
}

void setMap(string i)
{
    myMap[i]=0;
}

void addMap(string i)
{
    myMap[i]++;
}

这段代码运行良好,并为我提供了我想要的输出,但我并不热衷于添加 2 个额外的函数以使其工作或必须使地图成为全局。任何提示将不胜感激。

4

5 回答 5

5

没有额外功能并且没有全局地图的最简单方法是不使用for_each。

for_each (myVector.begin(), myVector.end(), setMap);
for_each (myVector.begin(), myVector.end(), addMap);

变成

map<string, int> myMap;
for (vector<string>::iterator i = myVector.begin(); i != myVector.end(); ++i)
    myMap[*i]=0;
for (vector<string>::iterator i = myVector.begin(); i != myVector.end(); ++i)
    ++myMap[*i];

完成后,您还可以删除第一个循环

map<string, int> myMap;
for (vector<string>::iterator i = myVector.begin(); i != myVector.end(); ++i)
    ++myMap[*i];

因为无论如何地图值都会被初始化为零。

是什么让您认为无论如何都必须使用 for_each?

于 2013-04-18T21:35:33.287 回答
3

那这个呢?将计数机制封装在单独的函数中以实现可重用性。

// Iterator pair based interface
template <class Iterator>
std::map<typename Iterator::value_type,int>
count(Iterator begin, Iterator end) {
    std::map<typename Iterator::value_type,int> counts;
    for (Iterator i = begin; i != end; ++i)
        counts[*i]++;
    return counts;
}

// Sequence interface
template <class Sequence>
inline std::map<typename Sequence::value_type,int>
count(Sequence seq) {
    return count(seq.begin(), seq.end());
}

然后像这样简单地使用它:

// C++11
for (const auto & c : count(myVector))
    cout << c->first << '\t' << c->second << endl;

// C++03
std::map<string,int> counts = count(myVector);
for (std::map<string,int>::const_iterator c = counts.begin(), e = counts.end(); c != e; ++c)
    cout << c->first << '\t' << c->second << endl;

简单的演示

于 2013-04-18T21:34:12.527 回答
3

你的setMap功能是不必要的。

如果地图的键不存在,请考虑此函数的作用。

void addMap(string i)
{
    myMap[i]++;
}

该表达式myMap[i]将为您的地图添加一个新键。

由于值类型是int,这个新值将是int(),这是保证0

于 2013-04-18T21:34:46.113 回答
2

在 C++11 下,你可以这样做:

#include <string>
#include <unordered_map>
#include <iostream>

int main() {

    std::string myArray[6] = {"foo","foo","bar","roo","foo","bar"};

    std::unordered_map<std::string, size_t> m;
    for (const auto& s : myArray)
        ++m[s];

    for (const auto& p : m)
        std::cout << p.first << "\t" << p.second << std::endl;

}

这打印:

foo     3
bar     2
roo     1

这是有效的,因为如果还没有,它m[s]会自动插入sm

使用std::unordered_map(哈希表)可能比std::map(平衡树)便宜。


你可以在 C++03 下做一些非常相似的事情,除了上面显示的“for each”循环将被常规的“for”循环替换。

于 2013-04-18T21:46:14.583 回答
0
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <map>

using namespace std;

int main (int argc, char * const argv[]) {

    string myArray[]={"foo","foo","bar","roo","foo","bar"};
    int arr_length = 6;
    vector<string> myVector(myArray, myArray + arr_length);

    //Print contents of vector:
    copy(myVector.begin(), 
         myVector.end(), 
         ostream_iterator<string>(cout, " ")
    );

    cout << endl;



    map<string, int> myMap;

    vector<string>::iterator pos;
    for (pos=myVector.begin(); pos<myVector.end(); ++pos)
    {
        myMap[*pos] += 1;
    }

    map<string, int>::iterator mapPos;
    for (mapPos=myMap.begin(); mapPos != myMap.end(); ++mapPos) {
        cout << "word: " << mapPos->first << "\t"
             << "count: " << mapPos->second << endl;
    }




        return 0;
}


--output:--
foo foo bar roo foo bar 
word: bar   count: 2
word: foo   count: 3
word: roo   count: 1
于 2013-04-18T22:19:54.300 回答