Найти уникальные строки в C ++ и сгенерировать связанный вектор поиска - PullRequest
1 голос
/ 10 февраля 2012

A имеет вектор строк в c ++:

vector<string> myVect = {"A", "A", "A", "B", "B", "A", "C", "C", "foo", "A", "foo"};

Как я могу преобразовать это в вектор целых чисел, чтобы каждое целое число однозначно соответствовало строке в myVect?т.е. я хотел бы вектор

out = {0, 0, 0, 1, 1, 0, 2, 2, 3, 0, 3}

Кроме того, я хотел бы вектор уникальных строк, каждая позиция, соответствующая числу в out:

uniqueStrings = {"A", "B", "C", "foo"}

ПокаУ меня есть следующее:

  vector<string> uniqueStrings;   // stores list of all unique strings
  vector<int> out(myVect.size());

  for (int i = 0; i < myVect.size(); ++i)
  {

    // seeing if this string has been encountered before
    bool assigned = false;
    for (int j = 0; j < uniqueStrings.size(); ++j)
      if (!myVect.at(i).compare( uniqueStrings.at(j) ))
      {
        out.at(i) = j;
        assigned = true;
        break;
      }

    // if not, add new example to uniqueStrings
    if (!assigned)
    {
      uniqueStrings.push_back(myVect.at(i));
      out.at(i) = uniqueStrings.size();
    }

  }

Это работает, но наверняка должен быть лучший способ?

Ответы [ 3 ]

2 голосов
/ 10 февраля 2012

Используйте set.

# include <set>
...
set <string> uniqueStrings;
...
for (int i = 0; i < myVect.size(); ++i)
{
    uniqueStrings.insert(myVect[i]);
}
2 голосов
/ 10 февраля 2012

Продолжайте нажимать их на карте, где строка является ключом, а значение соответствует идентификатору каждой строки. Тогда значения вашей карты будут однозначно соответствовать строкам, а ключи будут уникальными строками.

1 голос
/ 10 февраля 2012

Вот более или менее полный пример того, как вы можете использовать std::map<> для поддержания соответствия уникальных строк целочисленному идентификатору:

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

using namespace std;


// a simple functor type that makes it easier to dump the contents of a 
//  container of simple values or a container of std::pair
struct dump
{
    template <typename K, typename V>
    void operator()( typename std::pair<K,V> const& x)
    {
        cout << x.first << " ==> " << x.second << endl;
    }

    template <typename T>
    void operator()( T const& x)
    {
        cout << x << endl;
    }
};



#define NUM_ELEM(x) (sizeof(x)/sizeof(x[0]))

char const* data[] = {"A", "A", "A", "B", "B", "A", "C", "C", "foo", "A", "foo"};

int main() {
    // intialize the data set
    vector<string> myVect( data, data + NUM_ELEM(data));

    cout << "dump of initial data set" << endl << endl;
    for_each( myVect.begin(), myVect.end(), dump());

    map<string,size_t> uniqueStrings;   // stores collection of all unique strings

    for (vector<string>::iterator i = myVect.begin(); i != myVect.end(); ++i) {
        // I'm using uniqueStrings.size() as a convenience here...
        // I just needed something to generate  unique ID's easily,
        // it might not be appropriate to use size() for your ID's in real life

        // this will insert the new mapping if there's not already one 
        uniqueStrings.insert( make_pair(*i, uniqueStrings.size()));
    }


    cout << endl << endl<< "dump of uniqueStrings" << endl << endl;
    for_each( uniqueStrings.begin(), uniqueStrings.end(), dump());

    // I'm not sure if you'd need this `out` vector anymore - you can probably just
    //  use the `uniqueStrings` map directly for this information (but that would
    //  depend on your specific needs)

    vector<int> out;
    for (vector<string>::iterator i = myVect.begin(); i != myVect.end(); ++i) {
        out.push_back( uniqueStrings[*i]);
    }

    cout << endl << endl << "dump of `out` vector" << endl << endl;
    for_each( out.begin(), out.end(), dump());

    return 0;
}
...