Function for adding integers, that belong for the same string

Greetings,

I need to make a program, that counts every integer, that belongs to the same string.

For example, in my data file this is written:
5
town park 50
riverside 20
riverside 30
riverside 40
town park 45

And the answer should be:

town park 95
riverside 90

I have put every single one of those in the data file into a structure Pathway
1
2
3
4
{
 String name;
 int time;
};



and after that I have put every single one in an array. The array works fine, but I can't seem to add the same strings without skipping a few. Here's my code


1
2
3
4
5
6
7
8
9
10
11
12
13
void Sort(int n, Pathway A[])
{
    for(int i=0;i<n;i++)
    {
        for(int j=1;j<n;j++)
    {
        if (A[i].name==A[j].name)
        {
            A[i].time=A[i].time+A[j].time;
            n--;
            }
        }
    }


I would be very grateful, if someone would tell me the proper way to add them.
I think the best way is to add the numbers when you read the file. In the sort function you should only sort the entries.
closed account (48T7M4Gy)
Depending where you are at in your c++ learning career a <map> might be useful. Stay with the struct and use name as the map key and the time as cumulative time using the <map> key functionality to determine whether a name already exists or whether a new entry is created.

http://www.cplusplus.com/reference/map/map/
Since I'd started on this before kemort's, as ever, astute observations arrived. So here goes ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# include <iostream>
# include <string>
# include <vector>
# include <map>
# include <sstream> //std::istringstream
# include <fstream> //std::ifstream
# include <utility> //std::pair
# include <functional> //std::ref

struct Pathway
{
    std::string m_name;
    int m_time;
    Pathway(const std::string& name, const int time)
        : m_name(name), m_time(time){}
};

std::ostream& operator << (std::ostream& os, const Pathway& p)
{
    os << p.m_name << " " << p.m_time << "\n";
    return os;
}

int main()
{
    std::ifstream inFile{"C:\\test.txt"};
    std::map<std::string, int> pathMap{};
    std::vector<Pathway> allPaths{};

    if(inFile)
    {
        std::string dummy{};
        getline(inFile, dummy);
        //first line has number of entries, read it into dummy
        std::string line{};
        while (getline(inFile, line))
        {
            auto last_index = line.find_last_not_of("0123456789");
            auto name = line.substr(0, last_index);
            auto timeString = line.substr(last_index + 1);

            std::istringstream stream{timeString};
            int time{};
            stream >> time;
            //convert string to int
            if (inFile)
            {
                auto itr = pathMap.find(name);
                if(itr == pathMap.end())
                //i.e. name doesn't exist in the map
                {
                    pathMap.insert((std::make_pair(std::ref(name), time)));
                }
                else
                {
                    itr -> second += time;
                    //increase the value by time
                }
            }
        }
    }
    for (const auto& elem : pathMap)
    {
        allPaths.emplace_back(Pathway(elem.first, elem.second));
        //construct Pathway objects in situ
    }
    for (const auto& elem : allPaths)std::cout << elem;
}
Last edited on
Since the model answer seems to imply no change of order (which would occur by default with a map) ...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;

//======================================================================

struct Pathway
{
   string name;
   int time;
};

//======================================================================

string trim( const string &s )         // remove spaces at beginning and end of string
{
   int i = s.find_first_not_of( " " );
   if ( i == string::npos ) return "";

   int j = s.find_last_not_of( " " );
   return s.substr( i, j - i + 1 );
}

//======================================================================

Pathway extractPath( string line )
{
   string name;
   int time;

   line = trim( line );  
   int pos = line.rfind( " " );
   name = trim( line.substr( 0, pos ) );
   stringstream( line.substr( pos + 1 )  ) >> time;
   return Pathway{ name, time };
}

//======================================================================

int main()
{
   vector<Pathway> paths;
   string line;
   bool found;
   int N;

   ifstream in( "datafile" );
   getline( in, line );
   stringstream( line ) >> N;

   for ( int i = 0; i < N; i++ )
   {
      getline( in, line );
      Pathway p = extractPath( line );

      // Compare with previous paths, but DON'T CHANGE ORDER
      found = false;
      int numpaths = paths.size();
      for ( int j = 0; j < numpaths; j++ )
      {
         if ( p.name == paths[j].name )
         {
            found = true;
            paths[j].time += p.time;
            break;
         }
      }
      if ( !found ) paths.push_back( p );
   }

   for ( Pathway p : paths ) cout << p.name << " " << p.time << '\n';
}

closed account (48T7M4Gy)
http://en.cppreference.com/w/cpp/container/unordered_map
closed account (48T7M4Gy)
Taking gunners very rapid response and valued lead here's a way using <unordered_map>'s

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <fstream>
#include <unordered_map>

struct Pathway
{
    std::string name;
    int time;
};

int main()
{
    std::unordered_map<std::string, Pathway> pathMap;
    std::ifstream myfile ("time_map.txt");
    
    if (myfile.is_open())
    {
        std::string line;
        Pathway temp;
        
        while ( getline (myfile,line) )
        {
            std::string::size_type found = line.find_last_of(' ');
            
            temp.name = line.substr(0,found);
            temp.time = stoi( line.substr(found + 1) );
            
            // Check if name already exists in map
            auto it = pathMap.find(temp.name);
            if(it != pathMap.end())
                it->second.time += temp.time;
            else
                pathMap.emplace(temp.name, temp);
        
        }
        myfile.close();
        
        // Display map contents
        for(auto it:pathMap)
            std::cout
            << "Name: " << it.second.name
            << " Cumulative time: " << it.second.time << '\n';
    }
    else
        std::cout << "Unable to open file\n";
    
    return 0;
}


Name: riverside Cumulative time: 90
Name: town park Cumulative time: 95
Program ended with exit code: 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;

//======================================================================

string trim( string s )                // remove spaces at beginning and end of string
{
   int i = s.find_first_not_of( " " );   if ( i == string::npos ) return "";
   int j = s.find_last_not_of ( " " );
   return s.substr( i, j - i + 1 );
}

//======================================================================

struct Pathway
{
   string name;
   int time;
};

ostream& operator<<( ostream& strm, Pathway  p )
{ 
   strm << p.name << " " << p.time;
   return strm;
}

istream& operator>>( istream& strm, Pathway& p )
{
   string line;
   getline( strm, line );
   line = trim( line );                // prevent spurious spaces screwing up the next line
   int pos = line.rfind( " " );
   p.name = trim( line.substr( 0, pos ) );
   stringstream( line.substr( pos + 1 )  ) >> p.time;
   return strm;
}

void operator<<( vector<Pathway>& paths, Pathway p )
{
   for ( Pathway& q : paths )
   {
      if ( p.name == q.name )
      {
         q.time += p.time;
         return;
      }
   }
   paths.push_back( p );
}

//======================================================================

int main()
{
   vector<Pathway> paths;
   Pathway p;
   int N;

   ifstream in( "datafile" );
   in >> N;   in.ignore( 1000, '\n' );

   for ( int i = 0; i < N; i++ )
   {
      in >> p;
      paths << p;
   }
   in.close();

   for ( Pathway p : paths ) cout << p << '\n';
}


town park 95
riverside 90
Last edited on
closed account (48T7M4Gy)
Yet another way with arrays (unsorted).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <fstream>

struct Pathway
{
    std::string name;
    int time;
};

int main()
{
    std::ifstream myfile ("time_array.txt");
    
    if (myfile.is_open())
    {
        int no_entries = 0;
        std::string line;
        
        myfile >> no_entries;
        myfile.ignore();
        
        std::cout << no_entries << '\n';
        Pathway *array = new Pathway[no_entries];
        
        // Read in Pathways from file
        for(int i = 0; i < no_entries; i++)
        {
            std::getline(myfile, line);
            std::string::size_type found = line.find_last_of(' ');
            
            array[i].name = line.substr(0,found);
            array[i].time = stoi( line.substr(found + 1) );
            
        }
        myfile.close();
        
        // Process times for each separate Pathway
        for(int i = 0; i < no_entries; i++)
        {
            for(int j = i + 1; j < no_entries; j++)
            {
                if(array[j].name == array[i].name)
                {
                    array[j].time += array[i].time;
                    array[i].time = -1;
                    break;
                }
            }
        }
        
        //Display results
        for(int i = 0; i < no_entries; i++)
        {
            if(array[i].time != -1)
                std::cout << array[i].name << '\t' << array[i].time << '\n';
        }
        
        delete[] array;
    }
    else
        std::cout << "Unable to open file\n";
    
    return 0;
}
Topic archived. No new replies allowed.