Plz your help!

Hello,

I created a program doing the following thing:

Read from txt files, calculate a number called Div, set up a sorted general filename-Div list and write the sorted general filename-Div list to file

The app's code is the following:

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
#include <iostream>

Int main(){        
            map<string, int> m;

            for (int i = 0; i <= 9; i++)   
            {
                string st1 = "data00";
                string ext = ".txt";
                string filename;
                stringstream ss;
                ss << i;
                filename = st1 + ss.str() + ext;

                ifstream fin(filename);
                if (!fin) {
                    return (cout << "cannot open file\n"), 1;
                }
                vector<Pairs> v1;
                for (Pairs p; fin >> p; v1.push_back(p));
                fin.close();
            }
            for (int i = 10; i <= 99; i++)
            {
                string st1 = "data0";
                string ext = ".txt";
                string filename;
                stringstream ss;
                ss << i;
                filename = st1 + ss.str() + ext;

                ifstream fin(filename);
                if (!fin) {
                    return (cout << "cannot open file\n"), 1;
                }
                vector<Pairs> v2;
                for (Pairs p; fin >> p; v2.push_back(p));
                fin.close();
            }
            for (int i = 100; i <150 ; i++)
            {
                string st1 = "data";
                string ext = ".txt";
                string filename;
                stringstream ss;
                ss << i;
                filename = st1 + ss.str() + ext;

                ifstream fin(filename);
                if (!fin) {
                    return (cout << "cannot open file\n"), 1;
                }
                vector<Pairs> v3;
                for (Pairs p; fin >> p; v3.push_back(p));
                fin.close();
            }
            v1.insert(end(v1), begin(v2), end(v2));
            v1.insert(end(v1), begin(v3), end(v3));

            
                int saveIndex1 = 0;
                for (int i = 1; i < v1.size(); i++)
                {
                    if (v1[saveIndex1].second > v1[i].second)
                    {
                        saveIndex1 = i;
                    }
                }
                int smallestvalue = v1[saveIndex1].second;

                int saveIndex2 = 0;
                for (int j = 1; j < v1.size(); j++)
                {
                    if (v1[saveIndex2].second < v1[j].second)
                    {
                        saveIndex2 = j;
                    }
                }
                int greatestvalue = v1[saveIndex2].second;


                int K = v1[saveIndex2].first - v1[saveIndex1].first;


                int Div = 1 / K;
                cout << "DIV is: " << Div << endl;
                m.insert(make_pair(filename, Div));
            }


Now, the compiler spotted some errors in my code, for instance:

1. There is a problem with concatenating the vectors
2. Whenever it tries to start open the files it always follows the if (!fin) {cout <<" cannot open file " << endl;}

Any kind of help would be much appreciated. Thanks
Last edited on
This compiles, but hasn't been tested. Is it close to what you want?

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
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <utility>
#include <vector>
#include <map>
#include <algorithm>
#include <iomanip>

using namespace std;

using Pairs = pair<int, int>;

istream& operator>>(istream& is, Pairs& p) {
	is >> p.first;
	is.ignore();
	return is >> p.second;
}

bool operator<(pair<string, int>& k, pair<string, int>& l) {
	return k.second < l.second;
}

Pairs operator-(const Pairs& p1, const Pairs& p2) {
	return {p1.first - p2.first, p1.second - p2.second};
}

int main() {
	const std::string fstem {"data"};
	const std::string ext {".txt"};
	const size_t lastFile {150};

	map<string, int> m;
	vector<Pairs> v1;

	Pairs largest {0, 0}, smallest {1000, 1000};

	for (int i = 0; i <= lastFile; ++i) {
		stringstream ss;

		ss << fstem << std::setw(3) << std::setfill('0') << i << ext;

		ifstream fin(ss.str());

		if (!fin)
			return (cout << "Cannot open file " << ss.str() << '\n'), 1;

		for (Pairs p; fin >> p; v1.push_back(p)) {
			if (p > largest)
				largest = p;

			if (p < smallest)
				smallest = p;
		}

		const auto K {largest - smallest};

		/*Calculate each Div number of each file and consecutively insert it to the map I defined in the beginning containing the filename and its Div number */
		const int Div {1 / K.first};	// INT - FROM A RECIPRICOL ????

		cout << "DIV is: " << Div << '\n';
		m.emplace(ss.str(), Div);
	}
}

Last edited on
Just wondering if it is possible to construct a fstream from a directory_iterator ? Then there would be no need to worry about what the individual files are named, this will simpilfy the code a lot.
f
https://en.cppreference.com/w/cpp/filesystem/directory_iterator

I will try to investigate this now, provided there are no other distractions in the current household :+)

Edit:

The 3rd ctor overload does take a fs::path, so maybe the above hypothesis will work.

https://en.cppreference.com/w/cpp/io/basic_fstream/basic_fstream
Last edited on
@seeplus: many thanks seeplus. My enguiries are as follows:

1. The ss << fstem << std::setw(3) << std::setfill('0') << i << ext; gives something like
data0i, where i goes from 0 to 150 , as far as I can understand. the problem is that i will not read the files (if this is the case) as the files have the name pattern dataijk, where i,j,k start from 000 and end up to 150.

2.
1
2
Pairs operator-(const Pairs& p1, const Pairs& p2) {
	return {p1.first - p2.first, p1.second - p2.second};

}

I only want to subtract the firsts of the minimum and maximum second pair, namely subtract the first of the minimum second pair from the first of the maximum second pair.

3. For the const int Div {1 / K.first} : What I want is to just use the K (which is the subtraction of the first of minimum second pair from the first of the maximum second pair), not the K.first. So is using the const int Div {1 / K} a good idea?
Last edited on
1. This gives data000.txt data001.txt data002.txt etc. The number is always of 3 digits right justified padded with 0's

2. Just use the result Pairs .first value.

3. Isn't K.first simply the subtraction of the first minimum from the first of the maximum? If this isn't want you want, can you provide an example.
@seeplus many thanks!
1.Yes stupid question, I should have noticed better the function of the file formating with the setw and setfill. My apologies.
3. No that's ok, it is the K.first simply the subtraction of the first minimum from the first of the maximum. However, when it comes to the Div number what I actually want is to divide the 1 by only the result from the subtraction between the two firsts. Should I specify this with K? I mean K is anyway largest - smallest , but, the largest - smallest is based on the seconds comparison, not the firsts, and since I only want to subtract the firsts and not the seconds I thought the following procedure:
A]define the max and min seconds
B]get their firsts
C]subtract their firsts, and therefore when K appears it will have to do only with the firsts anyway.

As far as I understand you wrote 1 / K.first because when you wrote K you subtracted both the firsts and the seconds and created a third pair which was the result of the subtraction. Therefore since only the firsts were to be used in K you specified K.first (if I got it well?). So here comes my question:

In case I eliminate the seconds from the following:

1
2
3
Pairs operator-(const Pairs& p1, const Pairs& p2) {
	return {p1.first - p2.first, p1.second - p2.second};
}


, and the subtraction K {largest - smallest}; is performed only to the firsts, when I reach to div=1/K, should I use K.first in this case or just K?

In addition, when I use only the firsts in the subtraction operator and erase the seconds it states error E0289 --> no instance of constructor std::pair..... matches the argument list

EDIT:

1. I think I understand why you wrote it that wey with K.first and subtraction operator

2. I integrated the code to the rest of my program and compiles fine, but, it still does the same with what it did previously with my code: when it tries to open the first file "data000.txt" it terminates with the file open failure message!
Last edited on
Something seems not right re K. Pairs use int. Largest and smallest are pairs of int. large.first - small.first is an int. DIV is an int. 1 / (an int) is either 0 if abs(int) > 1 or 1 or -1 if (an int) is 1 or -1.

Is DIV to be only -1, 0, 1 what you want?
No it can be any number, negative or positive, and more precisely a double. Anyway, I'll leave the operator with both the subtraction of firsts and seconds, either way by using the K.first I don't care what is the second of the temporary pair created by the subtraction, only the first one. What is more disturbing is that it does the same thing again and can't open the files, not even the first one "data000".

EDIT:

Since the data files are writen with commas inside like this

A,B
D,C
E,H
etc...

Should I better use getline with ' , ' instead of the ss << fstem << etc... ??
Last edited on
No it can be any number, negative or positive, and more precisely a double


Then you need to change int in the program to double!

Should I better use getline with ' , ' instead of the ss << fstem << etc... ??


?? getline() is input (stream extraction). << is output (stream insertion)

For stream extraction, in this case I'd use >> over getline() as >> will do the stream -> number conversion, whereas with getline() you have to do it yourself. Are you concerned about performance or..?
Yes I changed the int -->double from the start

To be honset my problem is why the heck the app does not read from the data files the comma seperated values and put them into pairs each, but it keeps returning the annoying "Cannot open file " data000.txt
Last edited on
the app does not read from the data files
Most likely: The files are not where the program expects them because the file names are relative. Either you change the current path or you use absolute path.
Thanks Coder. Didn't think of that actually since the files are in the same folder as the application and I thought it will open them without specifying the path. Any ideas of how would I set the path with the use of stringstream or should I change the way I read from the files to integrate the current path?

EDIT:
I am asking this because I added one more const string with the rest of the current path right after the ss << but it reads incorrectly formed universal character name

EDIT2:

Ok, it required double backslash instead of single for C++ strings
Last edited on
if your console is in the folder, the program is in the folder, and the files are in the folder, you don't need the paths.
if you are in another folder in the console, and type pathname/program it looks in the folder your console is in, not where the program is in. You can hack around that, eg if you want it to always be the same folder the program is in regardless of where you kicked it off, then you can add a ./ (. is the current folder path) to make it work (rather than hard code a specific path).

in a gui, if you double click something to start it, the path can be off there too, if you have a shortcut/link to it or batch/script etc it can mess up as well.

visual is well known to stuff the exe 'over there' (debug and release folders which may also be under 'build type' folder eg x64/release/program.exe ) which can confuse the paths between debug and release builds etc. I think the IDE fixes it for you, but the console may need some TLC to get see the data files.

maybe some of this will help if you do not want to hard code a path.

there may be ways to make use of the command line params to do path things as well, eg provide it a folder from there and target any folder (default to where exe lives, maybe?)
Last edited on
Hello Jonnin! Oddly enough this isn't the case here. I had them in the same folder and the app couldn't find them. When I set the current path and tried again it worked just fine. I don't know why, it is the first time that is happening to me.
Hi,

As I alluded to earlier, this code iterates through every file in a directory, and puts pair data into a vector, I haven't done any of the other logic. The input file names are irrelevant, but one may want to put a regex in the directory iterator so it only does *.csv files, say. The iterator works with a sub-directory "csvfiles" in the first for loop, would be better if an absolute path was specified there. On my machine Linux VSCodium seems to read/write files relative to the cwd of the terminal, not the build directory, which was surprising.

The code is a bit dirty, it took me ages to figure out how to use the directory iterator. Good Luck !!

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
#include <fstream>
#include <iostream>
#include <filesystem>
#include <string>
#include <vector>

namespace fs = std::filesystem;

int main() {

    std::vector<std::pair<int,int>> ThePairs;

    for(auto& p: fs::directory_iterator("csvfiles")) {
        
        std::fstream InputFile;

        InputFile.open(p.path(), std::ios::in);
        // std::cout << p.path() << '\n'; 
        int a;
        int b;
        char comma;

        while (InputFile >>a>>comma>>b) {
            ThePairs.emplace_back(a,b);

        } ;
    }

    for(const auto& Item : ThePairs) {
        std::cout << Item.first << " " << Item.second << "\n";
    }
}
TheIdeasMan thanks a lot. I will study the code given that I have no idea about the filesystem library and the directory_iterator. And if it took ages to you I think I will figure it out in the next life since my level on C++ is not excellent.

Thanks anyway!
No worries, you can read all about it at this link:

https://en.cppreference.com/w/cpp/filesystem

It requires c++17. If you haven't looked at cppreference before, now is a good time to start, it is the first port of call for hundreds of thousands of developers and others.

The filesystem library generally deals with files and directories as a whole, the tricky part was associating a directory entry with an ordinary fstream. In the the end it is quite easy, as you can see from the code.

All the directory_iterator does is visit every file in the specified directory. This is ideal for your project: now you don't have to worry about the filename, in order to read from it. As mentioned earlier, it would be good to restrict it to *.csv files, and have some error processing if it isn't in that format. p.path() is the filename, so just need to compare that with a regex that is *.csv

I think I will figure it out in the next life since my level on C++ is not excellent.


All you have to do, is add in the rest of the logic for your problem, which you already have from the excellent posts from seeplus
Topic archived. No new replies allowed.