Write Scores into A vector from a textfile

Greetings On my code I a trying to read data from a file and store it in a vector highs_core
define like this as a struct that get a name, last name and score.
Now want to get data from textfile

1 name1 lastname1 100
2 name2 lastname2 90
3 name3 lastname3 80
4 name4 lastname4 70


want to take these data only the name last name and score and store in a file.



using high_score_list = std::vector<high_score> ;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
std::istream& operator>>(std::istream& ifs, high_score& hs) {
    std::string word;
    if (ifs) {
        while (ifs >> word){
            std::cout<<word + " \n ";
            ifs>>hs.first_name>>hs.last_name>>hs.score;
        }
    }

    return ifs;
}

void high_score::LoadHS(std::ifstream& ifs, high_score_list& hs){
    high_score qz;
    while(ifs >> qz)
        std::cout<<qz.last_name;
        hs.emplace_back(qz);
}


So please help me I am not that familiar with operators so been trying to get them out but my vector never updates
Last edited on
Hello SITHESH,

Looking at your code indenting line 17 does not make it part of the while loop. This works in Python, but not C++.

What your code actually looks line is:
1
2
3
4
5
6
7
8
9
10
11
void high_score::LoadHS(std::ifstream& ifs, high_score_list& hs)
{
    high_score qz;

    while (ifs >> qz)
    {
        std::cout << qz.last_name;
    }

    hs.emplace_back(qz);
}

Although the {}s are not need for an if statement, for loop or while loop with just 1 line it does help to include them. First you can see what is part of the while loop and 2nd if you add to the block you do not have to remember to add them.

In this case the "emplace_back()" will only add the last read to the vector. Not what you want.

In what you posted for the file is the 1st column of numbers in the file or was that for here?

The overloaded extraction operator looks like it should work, but there is not enough code to test it and I have no idea what you have done.

It really helps to post enough code to test what you are having a problem with. Also there may be something somewhere else that is wrong and you may not have found it yet, but someone else may.

Andy

Edit: typos.
Last edited on
Here Is the Code
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

Header File.

//
// Created by Sithe on 6/2/2021.
//
#include <iostream>
#include <string>
#include <vector>
struct high_score{
    std::string first_name, last_name;
    int score;
    /*friend std::ostream& operator<<(std::ostream&, const high_score&);
    friend std::istream& operator>>(std::istream& ifs, high_score& hs)*/;
    using high_score_list = std::vector<high_score> ;
    void add_high_score( high_score_list& hs_list, const std::string& ,const std::string& , int  );
    void writeToFile(const high_score_list& hs_list);
    static void do_sort(high_score_list&  );
    void do_print(const high_score_list& , std::ostream& stm);
 /*   void LoadHS(std::ifstream& ifs, high_score_list &);*/

};



#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <fstream>
#include "high_scores.h"

std::ostream& operator<< ( std::ostream& stm, const high_score& hs ) {
    return stm << hs.first_name << ' ' << hs.last_name << ' ' << hs.score ;
}

std::vector<high_score> high_score_list;

// add a high score to the vector
void high_score::add_high_score( high_score_list& hs_list, const std::string& first_name,
                     const std::string& last_name, int score ) {

    hs_list.push_back( { first_name, last_name, score } ) ;
}
void high_score::writeToFile(const high_score_list& hs_list){
    std::ofstream outputFile;
    high_score high_scores;
    const auto& do_sort(hs_list);
    outputFile.open("users.txt", std::ios::app);
    for (int j = 0; j < hs_list.size(); ++j) {
        high_scores=hs_list.at(j);
        outputFile<<(j+1)<<" " << high_scores.first_name << " " << high_scores.last_name << " " <<high_scores.score  <<std::endl;
    }
}

// sort the vector in descending order of scores
void high_score::do_sort( high_score_list& hs_list ) {
    std::sort( std::begin(hs_list), std::end(hs_list),
               []( const high_score& a, const high_score& b ) { return a.score > b.score ; } ) ;
}

// print the high score list with rank
void high_score::do_print( const high_score_list& hs_list, std::ostream& stm = std::cout ) {
    auto hs_list_cpy = hs_list ; // make a copy
    do_sort(hs_list_cpy) ; // sort the copy
    // print each item along with its rank
    for( std::size_t i = 0 ; i < hs_list_cpy.size() ; ++i ) {

        const auto rank = i+1 ; // index i is zero-based, but our rank is one-based
        stm << rank << ". " << hs_list_cpy[i] << '\n' ;
    }
}
std::istream& operator>>(std::istream& ifs, high_score& hs) {
    std::string word;
    if (ifs) {
        while (ifs >> word){
            std::cout<<word + " \n ";
            ifs>>hs.first_name>>hs.last_name>>hs.score;
        }
    }

    return ifs;
}

void high_score::LoadHS(std::ifstream& ifs, high_score_list& hs){
    high_score qz;
    while(ifs >> qz)
        std::cout<<qz.last_name;
        hs.emplace_back(qz);
}

int main() { 

    high_score_list scores ;
    high_score highS;
    highS.add_high_score( scores, "abc", "def", 22 ) ;
}



Now only interested In just reading the file From a textile then store them in a vector that every time a person plays a game i use the textile to add the new player to the list based on the score.
As a first revision, consider:

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <algorithm>

struct high_score;
using High_Score_List = std::vector<high_score>;

struct high_score {
	std::string first_name, last_name;
	int score {};

	static void add_high_score(High_Score_List& hs_list, const std::string&, const std::string&, int);
	static void writeToFile(const High_Score_List& hs_list);
	static void do_print(const High_Score_List&, std::ostream& stm);
	static void LoadHS(High_Score_List &);
	static void do_sort(High_Score_List&);
};

std::ostream& operator<< (std::ostream& stm, const high_score& hs) {
	return stm << hs.first_name << ' ' << hs.last_name << ' ' << hs.score;
}

// add a high score to the vector
void high_score::add_high_score(High_Score_List& hs_list, const std::string& first_name,
	const std::string& last_name, int score) {

	hs_list.emplace_back(first_name, last_name, score);
}

void high_score::writeToFile(const High_Score_List& hs_list) {
	std::ofstream outputFile("users.txt"/*, std::ios::app*/);
	auto hs_list_cpy {hs_list}; // make a copy

	do_sort(hs_list_cpy);

	for (size_t j = 0; j < hs_list_cpy.size(); ++j) {
		const auto& high_scores {hs_list_cpy[j]};

		outputFile << (j + 1) << " " << high_scores.first_name << " " << high_scores.last_name << " " << high_scores.score << '\n';
	}
}

// sort the vector in descending order of scores
void high_score::do_sort(High_Score_List& hs_list) {
	std::sort(std::begin(hs_list), std::end(hs_list),
		[](const high_score& a, const high_score& b) { return a.score > b.score; });
}

// print the high score list with rank
void high_score::do_print(const High_Score_List& hs_list, std::ostream& stm = std::cout) {
	auto hs_list_cpy {hs_list}; // make a copy

	do_sort(hs_list_cpy); // sort the copy

	// print each item along with its rank
	for (std::size_t i = 0; i < hs_list_cpy.size(); ++i)
		stm << i + 1 << ". " << hs_list_cpy[i] << '\n';
}

std::istream& operator>>(std::istream& ifs, high_score& hs) {
	int rank {};

	ifs >> rank >> hs.first_name >> hs.last_name >> hs.score;

	return ifs;
}

void high_score::LoadHS(High_Score_List& hs) {
	std::ifstream ifs("users.txt");

	for (high_score qz; ifs >> qz; )
		hs.emplace_back(qz);
}

int main() {
	High_Score_List scores;
	high_score highS;

	highS.add_high_score(scores, "abc", "def", 22);
	highS.add_high_score(scores, "xyz", "uvw", 62);
	highS.do_print(scores);

	highS.writeToFile(scores);

	scores.clear();
	highS.LoadHS(scores);
	highS.do_print(scores);
}

Thank you at @seeplus now I got sense over this and finally I feel like I have completed the task now thank you for your HELP really appreciate it VERY much.
Hello SITHESH,

Sorry this too me longer than I first thought. I had trouble keeping track os some of the variable names because they are so close.

This is what I came up with for the header file:
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
//
// Created by Sithe on 6/2/2021.
//
//#include <iostream>
//#include <string>
//#include <vector>

#ifndef HIGH_SCORE_H  // <--- Added.
#define HIGH_SCORE_H

struct High_score;
using HIGH_SCORE_LIST = std::vector<High_score>;  // <--- Changed.

struct High_score  // <--- Changed.
{
    std::string first_name, last_name;
    int score;

    /*friend std::ostream& operator<<(std::ostream&, const high_score&);
    friend std::istream& operator>>(std::istream& ifs, high_score& hs)*/;
    void add_high_score(HIGH_SCORE_LIST& hs_list, const std::string&, const std::string&, int);
    void writeToFile(const HIGH_SCORE_LIST& hs_list);
    static void do_sort(HIGH_SCORE_LIST&);
    void do_print(const HIGH_SCORE_LIST&, std::ostream& stm);
    void LoadHS(std::ifstream& ifs, HIGH_SCORE_LIST &);
};
#endif // !HIGH_SCORE_H 

With the using statement and since you are defining a user variable the capital letters do help.

For a class or struct the name works better when you start it with a capital letter. It also helps with functions.

I did this for "main":
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
int main()
{
    const std::string inFileName{ "Scores.txt" };  // <--- Put File name here.

    std::ifstream inFile(inFileName);

    if (!inFile)
    {
        std::cout << "\n     File " << std::quoted(inFileName) << " did not open.\n";  // <--- Requires header file "<iomanip>".
        //std::cout << "\n     File \"" << inFileName << "\" did not open.\n";

        return 1;
    }

    HIGH_SCORE_LIST scores;

    High_score highS;

    highS.LoadHS(inFile, scores);

    highS.add_high_score(scores, "abc", "def", 22);
    highS.add_high_score(scores, "pqr", "xyz", 101);

    highS.do_print(scores);

    highS.writeToFile(scores);

    //highS.do_print(scores);

    return 0;  // <--- Not required, but makes a good break point for testing.
}

Setting up the input file first if there is a problem you leave the program before you get into anything else. Also when you open the output file stream you should check it and not just count on it working.

The problem starts with line 19. Not that the function call is a problem, but the function.

Once you call the "LoadHS" function, your code:
1
2
3
4
5
6
7
void high_score::LoadHS(std::ifstream& ifs, HIGH_SCORE_LIST& hs)
{
    high_score qz;
    while (ifs >> qz)
        std::cout << qz.last_name;
    hs.emplace_back(qz);
}

The while loop is partly correct. line 6 needs to be part of the while loop not by its-self.

The next problem comes when the while condition uses the overloaded extraction operator, (>>), and that function, You have:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
std::istream& operator>>(std::istream& ifs, high_score& hs)
{
    std::string word;
    if (ifs)
    {
        while (ifs >> word)
        {
            std::cout << word + " \n ";
            ifs >> hs.first_name >> hs.last_name >> hs.score;
        }
    }

    return ifs;
}

Since the file stream has already been opened and checked in "main" you can do without the if statement.The while loop is reading the whole file and line 13 only returns the last read. This function should read only 1 line at a time and return it back to the "LoadHS" function to process.

I ended up with:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
std::istream& operator>>(std::istream& ifs, High_score& hs)
{
    std::string rank;

    ifs >> rank >> hs.first_name >> hs.last_name >> hs.score;

    std::cout << "\n " << rank << ' ';

    return ifs;
}

void High_score::LoadHS(std::ifstream& ifs, HIGH_SCORE_LIST& hs)
{
    High_score tempHighScore;

    while (ifs >> tempHighScore)
    {
        std::cout << tempHighScore.last_name;

        hs.emplace_back(tempHighScore);
    }

    //std::cout << '\n'; // <--- Used as a break point for testing.
}

I have not changed it yet, but the "emplace_back" in line 20 can be a "push_back" because you already have an object of the struct constructed and ready to use.

You will notice that I have changed some of the variable names to make it easier to follow.

The "print" function works well and sorts a copy of the vector before it prints it out.

In the "writeToFile" I had a problem with the sort until I changed it to work like the "print" function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void High_score::writeToFile(const HIGH_SCORE_LIST& hs_list)
{
    std::ofstream outputFile;
    outputFile.open("users.txt"/*, std::ios::app*/);
    // <--- How do you know its open without checking?
    
    High_score high_scores;

    //const auto do_sort(hs_list);
    auto hs_list_cpy = hs_list; // make a copy

    do_sort(hs_list_cpy); // sort the copy

    for (size_t idx = 0; idx < hs_list.size(); ++idx)
    {
        high_scores = hs_list[idx];  // <--- The for loop eliminates the need for "at()".

        outputFile << (idx + 1) << " " << hs_list_cpy[idx];
        /*outputFile << (idx + 1) << " " << high_scores.first_name << " " << high_scores.last_name << " " << high_scores.score << std::endl;*/
    }
}

You wrote a function to overload the insertion operator, (<<), but never use it. Line 18 makes use of the overloaded (<<) operator.

Lastly I did this with the include files:
1
2
3
4
5
6
7
8
9
#include <iostream>
#include <iomanip>  // <--- Added.
#include <string>
#include <vector>

#include <algorithm>
#include <fstream>

#include "high_scores.h" 


Andy
@Andy Thank you very much for your help, Really a lot now makes sense really did not care much about readability only was concerned with either the code is running or not if yes does it gives Logical error if no then done if yes how to debug but such help now and then not just to fix the bug but to write a good code and readable is really appreciated.

Thank you. 👏👏
Topic archived. No new replies allowed.