C++ группирование повторений в векторе

у меня есть файл, структурированный следующим образом:

A 123456 0
G 123456 5
A 235334 0
B 123456 2

каждая часть информации хранится вот так:

temp.code >> temp.personid >> temp.data

Я сохранил эту информацию в векторе

 ifstream fin("test.txt");
 vector<TestClass> test;
 TestClass temp;
 string line;
 while (getline(fin, line)) {//.. test.push_back(temp);}

данного personid может всплывать много раз в файле. То, что я хочу сделать, это перебрать вектор и группы повторов в один объект класса в personid, моя цель состоит в том, что я хочу суммировать данные для каждого конкретного объекта таким образом, выход для файла выше будет:

123456 : 7
235334 : 0

что было бы элегантным способом подойти к этому?

спасибо

2 ответов


в следующем коде используется std::unordered_map как уже предлагалось комментариями. Он будет читать файл построчно.
Код предполагает, что идентификатор человека имеет тип int код типа std::string и данные типа int.

он вставляет каждый Person (здесь как пример структуры) в карту. Если идентификатор человека уже существует, он будет суммировать данные. Это означает, что это решение не использует временное std::vector но только std::unordered_map.

см. живой пример с вашими данными на ideone.com.

код:

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <unordered_map>

struct Person
{
   std::string code;
   int         data;
};

typedef std::unordered_map<int, Person> PersonMap;

int main()
{
   std::ifstream fin("test.txt");

   PersonMap persons;

   /* line by line reading */
   for (std::string line; std::getline(fin, line); )
   {
      std::istringstream iss(line);

      int    personId;
      Person personData;

      /* parse line as std::string, int, int */
      iss >> personData.code >> personId >> personData.data;

      /* insert into map and save result */
      std::pair<PersonMap::iterator, bool> insertResult =
         persons.insert(std::pair<int, Person>(personId, personData));

      /* if personId is already there */
      if (!insertResult.second)
      {
         insertResult.first->second.data += personData.data;
      }
   }

   /* output whole map */
   for(auto const &person : persons)
   {
      std::cout << person.first << " : " << person.second.data << "\n";
   }
   std::cout << std::flush;
}

выход:

235334 : 0
123456 : 7

использовать неупорядоченный карту. Время поиска в неупорядоченной карте является постоянным O(1) в среднем случае. Я использовал вектор для выборочных данных, вы можете загружать данные из файла вместо вектора.

#include <bits/stdc++.h>
using namespace std;

int main() {
    unordered_map<string, int>m;
    unordered_map<string, int>::iterator itr;    // Iterator to iterate unordered map
    vector<pair<string, int> >person_details;    // pair of vector to represent sample data, you can load data from file instead
    person_details.push_back(make_pair("123456",0));
    person_details.push_back(make_pair("123456",5));
    person_details.push_back(make_pair("235334",0));
    person_details.push_back(make_pair("123456",2));
    for(int i=0;i<person_details.size();i++)
    {
        if(m.find(person_details[i].first) == m.end() )                // If personId is not present in map, insert it
            m[person_details[i].first]=person_details[i].second;
        else m[person_details[i].first]+=person_details[i].second;        // If personId is present in map, increment it.
    }
    for(itr=m.begin();itr!=m.end();itr++)          
        cout<<itr->first<<" "<<itr->second<<endl;       // Displaying personId with occurance
    return 0;
}

Output:
235334 0
123456 7

Примечание: Вы можете использовать карта постоянная O(LogN), где N - размер контейнера.