更容易计算向量中相同字符串的方法?

时间:2013-04-18 21:29:39

标签: c++ string map vector

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

#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个额外的函数来使其工作或者必须使地图全局化。我们将非常感激地收到任何提示。

5 个答案:

答案 0 :(得分: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呢?

答案 1 :(得分: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;

Simple demo

答案 2 :(得分:3)

您的setMap功能是不必要的。

如果地图的密钥不存在,请考虑此功能的作用。

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

表达式myMap[i]会为您的地图添加一个新密钥。

由于值类型为int,因此新值为int(),保证为0

答案 3 :(得分: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]会自动将s插入m(如果尚未插入)。

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


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

答案 4 :(得分: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