Printing out name of station that matches max and min temp in a file

Hello, I have a file that has a bunch of information in it about weather data. I currently need to find the max temp and the min temp and print out the stations that has these temps. So for example, if the max temp is 42, I need to print out into the terminal station random station name. I am not so sure how to print out just the station name.
The file has a format that looks like this but a lot more data:

STATION_NAME                                        DATE     PRCP     TMAX     TMIN
--------------------------------------------------- -------- -------- -------- --------
                       BANKHEAD LOCK AND DAM AL US  20180301 0.15     46.76    41.54
                       BANKHEAD LOCK AND DAM AL US  20180302 0.45     46.94    39.92
                       BANKHEAD LOCK AND DAM AL US  20180303 0.00     46.94    37.94
                       BANKHEAD LOCK AND DAM AL US  20180304 0.00     46.76    37.94
                       BANKHEAD LOCK AND DAM AL US  20180305 0.00     43.70    38.48
                       BANKHEAD LOCK AND DAM AL US  20180306 1.36     43.88    38.66
                       BANKHEAD LOCK AND DAM AL US  20180307 0.41     41.72    38.12
                       BANKHEAD LOCK AND DAM AL US  20180308 0.00     41.18    37.22
                       BANKHEAD LOCK AND DAM AL US  20180309 0.00     41.36    37.22

Here is the code I have so far.
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
 #include <iostream>
#include <fstream>
#include <iomanip>
#include <string>

using namespace std;

int main(void)
{
	// Variables

	string dataline = "";
	string station_s = "", date_s = "", tmax_s = "", tmin_s = "", prcp_s = "";

	unsigned int pos_tmax = 0;
	unsigned int pos_tmin = 0;
	unsigned int pos_prcp = 0;
	unsigned int pos_station = 0;
	unsigned int pos_date = 0;
	float tmax = 0, tmin = 0, prcp = 0; // Real types for temps
	int bad_records = 0; // Count the records with bad data for tmax and tmin

	float max = 0;
	float min = 100;

	ifstream infile; // Input file pointer
	ofstream outfile; // Output file pointer

	cout << "WEATHER STATION DATA" << endl;
	cout << "Open the data file." << endl;
	infile.open("C:/Users/jerie/Downloads/weather_station_five_column.txt");

	if (!infile)
	{
		cout << "Unable to open the input file. " << endl;
		system("pause");
		return 1;
	}
	cout << "Weather data file opened." << endl;

	cout << "Use the first line of the file to find the column positions. " << endl;
	getline(infile, dataline);
	string heading = "STATION_NAME                                        DATE     PRCP     TMAX     TMIN";
	

	// Use firest line of file (header) to find max and min temp columns

	pos_tmax = dataline.find("TMAX");
	if (pos_tmax <= dataline.length())
	{
		cout << "TMAX begins at column: " << pos_tmax << endl;
	}
	else
	{
		cout << "TMAX was not found - terminating." << endl;
		system("pause");
		return 3;
	}

	pos_tmin = dataline.find("TMIN");
	if (pos_tmin <= dataline.length())
	{
		cout << "TMIN begins at column: " << pos_tmin << endl;
	}
	else
	{
		cout << "TMIN was not found - terminating." << endl;
		system("pause");
		return 4;
	}

	pos_prcp = dataline.find("PRCP");
	if (pos_prcp <= dataline.length())
	{
		cout << "TMIN begins at column: " << pos_prcp << endl;
	}
	else
	{
		cout << "prcp was not found - terminating." << endl;
		system("pause");
		return 5;
	}
	pos_station = dataline.find("STATION_NAME");
	pos_date = dataline.find("DATE");

	cout << "Read the second line from the file - dashes. " << endl;
	getline(infile, dataline);


	while (!infile.eof())
	{
		getline(infile, dataline);
		// Add this to check for empty lines
		if (dataline.length() < 50)
		{
			cout << "Short line detected of length " << dataline.length() << endl;
			continue; // Skip to the end of the loop.
		}
		// Read tmax and tmin as strings
		tmax_s = dataline.substr(pos_tmax, 5);
		tmin_s = dataline.substr(pos_tmin, 5);
		prcp_s = dataline.substr(pos_prcp, 5);
		station_s = dataline.substr(pos_station, 50);
		date_s = dataline.substr(pos_date, 8);

		tmax = stof(tmax_s);
		tmin = stof(tmin_s);
		prcp = stof(prcp_s);

		if (tmax > max)
		{
			max = tmax;
		}
		if (tmin < min)
		{
			min = tmin;
		}
	}
	cout << "Max: " << max << endl;
	cout << "Min: " << min << endl;

	//string max_s = to_string(max);
	//string min_s = to_string(min);
	//cout << max_s << endl;
	//cout << min_s << endl;
	
	infile.clear();                 // clear fail and eof bits
	infile.seekg(0, std::ios::beg); // back to the start!
	
	getline(infile, dataline);
	getline(infile, dataline);

	while (!infile.eof())
	{
		getline(infile, dataline);
		if (dataline.length() < 50)
		{
			cout << "Short line detected of length " << dataline.length() << endl;
			continue; // Skip to the end of the loop.
		}
		
		tmax_s = dataline.substr(pos_tmax, 5);
		tmin_s = dataline.substr(pos_tmin, 5);
		prcp_s = dataline.substr(pos_prcp, 5);
		station_s = dataline.substr(pos_station, 50);
		date_s = dataline.substr(pos_date, 8);
		

		tmax = stof(tmax_s);
		tmin = stof(tmin_s);
		prcp = stof(prcp_s);
		/*find the position of when temp is max. grab that max. so when max(string) is found print out station*/

		
	}
	
	infile.close();

	return 0;



}
Last edited on
> max = tmax;
Well at the same time as you do this, you also do
station_max = station_s;

https://en.cppreference.com/w/cpp/io/basic_ios/eof
while (!infile.eof())
eof doesn't do what you think it does.
It is a state (the result of a past event), not a prediction (of a future event).
If you have a file with 10 chars, and you read 10 chars, then eof() will still be false. It's only on the failure of the 11th read that eof() will become true.

So instead, you write
1
2
3
while ( getline(infile, dataline) ) {
  // do stuff
}
As a first refactor, possibly:

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 <string>

size_t trunc(const std::string& str, size_t strt) {
	auto pos {strt};

	for (; str[pos] == ' '; ++pos);
	return pos;
}

int main() {
	std::cout << "WEATHER STATION DATA\n";

	std::ifstream infile("weather.txt");

	if (!infile)
		return (std::cout << "Unable to open the input file.\n"), 1;

	float max {};
	float min {100};
	std::string max_stat {};
	std::string min_stat {};
	std::string dataline;

	std::getline(infile, dataline);

	const auto pos_tmax {dataline.find("TMAX")};

	if (pos_tmax == std::string::npos)
		return (std::cout << "TMAX was not found - terminating.\n"), 2;

	const auto pos_tmin {dataline.find("TMIN")};

	if (pos_tmin == std::string::npos)
		return (std::cout << "TMIN was not found - terminating.\n"), 3;

	const auto pos_station {dataline.find("STATION_NAME")};

	if (pos_station == std::string::npos)
		return (std::cout << "STATION_NAME was not found - terminating.\n"), 4;

	std::getline(infile, dataline);

	while (std::getline(infile, dataline)) {
		if (dataline.length() < 50)
			std::cout << "Short line detected of length " << dataline.length() << '\n';
		else {
			try {
				const auto tmax {std::stof(dataline.substr(pos_tmax, 5))};
				const auto tmin {std::stof(dataline.substr(pos_tmin, 5))};

				if (tmax > max) {
					const auto pos {trunc(dataline, pos_station)};

					max = tmax;
					max_stat = dataline.substr(pos, 50 - (pos - pos_station));
				}

				if (tmin < min) {
					const auto pos {trunc(dataline, pos_station)};

					min = tmin;
					min_stat = dataline.substr(pos, 50 - (pos - pos_station));
				}
			}
			catch (...) {
				std::cout << "Invalid temperature reading\n";
			}
		}
	}

	std::cout << "Max: " << max << " at station " << max_stat << '\n';
	std::cout << "Min: " << min << " at station " << min_stat << '\n';
}

Ok right, that makes sense, not sure why I wasn't able to think of that. But I did realize that in the file, some of the stations have the same min temp. So two separate stations have both the min temp. How would I be able to print out both stations? Also, I would like to avoid trunc and auto pos since I am not so familiar with it yet and I would like to add more functions to this data file without having unknown errors because of it but thank you for allowing me to know these two exist.
Last edited on
Brute force method when you've calculated what the min and/or max temps are and multiple stations have the same min/max temps:

Reset the file's position back to the start. Loop through your stations and when a station's min/max temp matches the found min/max temp display that station.

Depending on the amount of data you can read the station data all at once, storing that data in a container. A std::vector works for storing a variable amount of data.

When you've stored your data in the container you calculate the min/max temp. Displaying possible multiple stations now doesn't involve any file I/O.

Another thing to consider if the file data is a repeating series of data points, as your posting indicates, use a struct to contain the multiple variables. Now your container can hold your struct so accessing gobs of data is easier to manage.
As the station name is right-justified, you need some way of left-trimming the string. That is what trunc (L5 -10) helps with. It returns the first non-space position to be used as the start position for substr(). std::isspace() could have been used instead of the test for ' '.

For multiple mins and maxs, the easiest is to maintain a vector for each containing the appropriate station names.

ie L57 becomes clear and add to the max vector, L64 clear and add to the min vector. You then need to test for tmax == max and tmin == min. If equal, then add to the appropriate vector.

Another way of getting rid of the preceding whitespace is:

while (std::getline(file >> std::ws, line) )
Topic archived. No new replies allowed.