C++ reading multiple input files sequentially - c++

I have 47 different files:
001_template.dat
...
047_template.dat
in a directory called /data. I need to compare each of these template files to three different query files, also in the directory. These are named:
001_AU01_query.dat
001_AU12_query.dat
001_AU17_query.dat.
I know how to get all of this to run, but I will have to cut and paste these 6 lines of code 46 more times and the program will get very long and confusing.
Is there a good way to loop over these files? Possibly by looping over the template files and then doing three queries for every template? I obviously have a similarity function and a sort function already defined, as well as inputFile. Here is the code I would like to convert: (not homework this is for a facial expression recognition project I have been working on)
int main()
{
vector<float> temp01;
vector<float> temp12;
vector<float> temp17;
temp01 = similar(inputFile("data/001_AU01_query.dat"), inputFile("data/001_template.dat"));
sortAndOutput(temp01);
temp12 = similar(inputFile("data/001_AU12_query.dat"), inputFile("data/001_template.dat"));
sortAndOutput(temp12);
temp17 = similar(inputFile("data/001_AU17_query.dat"), inputFile("data/001_template.dat"));
sortAndOutput(temp17);
}

Then I would go with creating the file names with sprintf into the loop:
char data[100];
char template[100];
char* datas[3] = {"%3d_AU01_query.dat", "%3d_AU12_query.dat", "%3d_AU17_query.dat"};
for(i=0; i<47; i++){
for{j=0; j<3; j++){
sprintf(template, "%03d_template.dat", i); // create the name of the template 1-47
sprintf(data, datas[j], i);
compare(template, data);
}
}
That should work as expected I think.

Use two arrays holding the names of files and templates and loop on them:
char* files[47] = {"file1", "file2", ...., "file47"};
char* templates[3] = {"template1", "template2", "template3"};
and loop on them:
for(i=0; i<47; i++){
for{j=0; j<3; j++){
compare(file[i],template[j]);
}
}

void work()
{
vector<float> temp;
char data[100];
char templates[100];
char* datas[3] = { "data/%03d_AU01_query.dat", "data/%03d_AU12_query.dat", "data/%03d_AU17_query.dat" };
for (int i = 1; i < 48; i++)
{
for(int j = 0; j < 3; j++)
{
sprintf_s(templates, "data/%03d_template.dat", i); // create the name of the template 1-47
sprintf_s(data, datas[j], i);
temp01 = similar(inputFile(data), inputFile(templates));
sortAndOutput(temp);
}
}
}

Related

Is there a way to count the number of ocurrences of each element of a string array?

I have the following code that does exactly what I want. The problem is that I need the sample array to compare the strings and keep the count. Is there a way to count the number of occurrences of each string on any array without a sample?
For a little bit more context, the initial problem was to read data from a .txt file including vehicles information, like:
Volkswagen Jetta
Ford Focus
Volkswagen Jetta
And count the number of vehicles of each brand. Keep in mind that this is from an introductory course for programming, and we don't know how to use vectors or maps.
#include <iostream>
#include <string>
using namespace std;
using std::string;
#define MAX 20
int main(){
int counter[MAX];
string arr[MAX]={"ABC","AOE","ADC","ABC","ADC","ADC"};
string sample[MAX]={"ABC", "AOE", "ADC"};
for(int i=0; i<=MAX; i++){
counter[i]=0;
}
for(int i=0; i<MAX;i++){
for(int j=0; j<MAX; j++){
if (sample[i]==arr[j]){
counter[i]++;
}
}
}
for(int i=0; i<3;i++){
cout<< sample[i] << "=" << counter[i]<<endl;
}
return 0;
}
All you are expected to do is keep a list (an array will do) of brand names, and an array of counts for each name:
std::string brand_names[100];
int counts[100]; // number of times each element of brand_names[] was read from file
int num_items = 0;
Each time you read a brand name from file, try to find it in the array of strings. If found, just add one to the count at the same index. If not found, add it to the end of the brand_names[] array, add 1 to the end of the counts[] array, and increment num_items.
You do not need anything more than a simple loop for this:
an outer loop to read the next brand name from file
an inner loop to try to find the brand name in the list
If you want to solve this problem without knowing the initial values of the sample array:
Create an empty sample array. When you see new elements add them to this array.
Use a variable sample_size to keep track how many samples have been seen. Below is a simple example which doesn't use std::vector or dynamic allocation.
int main()
{
std::string arr[MAX] = { "ABC","AOE","ADC","ABC","ADC","ADC" };
std::string sample[MAX];
int sample_size = 0;
int counter[MAX] = { 0 };
for (int i = 0; i < MAX; i++)
{
if (arr[i].empty()) break;
bool sample_found = false;
for (int j = 0; j < sample_size; j++)
if (arr[i] == sample[j])
{
sample_found = true;
counter[j]++;
break;
}
if (!sample_found)
{
sample[sample_size] = arr[i];
counter[sample_size]++;
sample_size++;
}
}
for (int i = 0; i < sample_size; i++)
cout << sample[i] << "=" << counter[i] << std::endl;
return 0;
}

C++ Convert one exact string element into an int

I want to create a string array and then after writing lines into it I want to change one exact character into int. I already know that all the characters are going to be numbers. As my goal is to change the one character at a time, options like atoi, stoi etc. are perhaps off? The closest I got is that:
#include <iostream>
int main()
{
int n=0,suma=0,i=0;
int multiplier[11]={1,3,7,9,1,3,7,9,1,3,1};
std::cin>>n;
std::string str[n];
for (int i = 0; i < n; ++i)
{
std::cin>>str[i];
}
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < 11; ++j)
{
i = str[i][j] - '0';
std::cout << i;
}
}
}
Although this is the output I get
"1-48"
I know that the string is going to be 11 characters long. Any ideas?
EDIT: It was a single typo that caused my confuse :p Yet still I'm looking forward to read and learn from your suggestions such as using different way to read n (from user input) strings. :)
In your loop:
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < 11; ++j)
{
i = str[i][j] - '0';
std::cout << i;
}
}
you are modifying outer loop variable i (looks like for the purpose of printing a value).
Given an unfortunate input, you would go out-of-bounds fast.

Assign values to a 2D vector from a file on c++

Im trying to assign values to a 2d vector, this is the way that i defined the vector, and also its important to say that rows and columns, are ints previously defined
vector < vector <int>> vec(rows , vector <int> (columns,0));
i want to assign to this vector, each char of a pbm file, this file only have '1' and '0', so this is the way im reading it
char i;
FILE* fp;
fp = fopen("file.pbm", "r");
on this way im assigning values to the vector
for (int h=0; h<rows; h++){
for (int j=0; j<columns; j++){
while((i=fgetc(fp))!=EOF){
vec[h][j] = i;
}
}
}
but when i try to print all the vector content, this one, only have '0'
for (int h=0; h<rows; h++){
for (int j=0; j<columns; j++)
cout << vec[h][j];
cout <<endl;
}
fclose(fp);
If anyone could tell me where im failing when i make this assignment, thanks!
vec[h][j] = i;
for (int h=0; h<rows; h++){
for (int j=0; j<columns; j++){
while((i=fgetc(fp))!=EOF){
vec[h][j] = i;
}
}
}
The while loop runs through the entire file without ever incrementing h and j so you are reading the whole file into the first element. And you are doing this (rows*columns) times.
You'll need to redesign your code to read the code in correctly.

Bug in selection sort loop

I need to make a program that will accept a input file of numbers(integer.txt) which will be sorted one number per line, into a vector, then use a selection sort algorithm to sort the numbers in descending order and write them to the output file (sorted.txt). I'm quite sure something is wrong in my selectionSort() function that is causing the loop not to get the right values, because after tested with cout I get vastly improper output. I'm sure it's a beginning programmer's goof.
vector<string> getNumbers()
{
vector<string> numberList;
ifstream inputFile ("integer.txt");
string pushToVector;
while (inputFile >> pushToVector)
{
numberList.push_back(pushToVector);
}
return numberList;
}
vector<string> selectionSort()
{
vector<string> showNumbers = getNumbers();
int vectorMax = showNumbers.size();
int vectorRange = (showNumbers.size() - 1);
int i, j, iMin;
for (j = 0; j < vectorMax; j++)
{
iMin = j;
for( i = j; i < vectorMax; i++)
{
if(showNumbers[i] < showNumbers[iMin])
{
iMin = i;
}
}
if (iMin != j)
{
showNumbers[j] = showNumbers [iMin];
}
}
return showNumbers;
}
void vectorToFile()
{
vector<string> sortedVector = selectionSort();
int vectorSize = sortedVector.size();
ofstream writeTo;
writeTo.open("sorted.txt");
int i = 0;
while (writeTo.is_open())
{
while (i < vectorSize)
{
writeTo << sortedVector[i] << endl;
i += 1;
}
writeTo.close();
}
return;
}
int main()
{
vectorToFile();
}
vectorRange defined but not used.
In your selectionSort(), the only command that changes the vector is:
showNumbers[j] = showNumbers [iMin];
Every time control reaches that line, you overwrite an element of the vector.
You must learn to swap two values, before you even think about sorting a vector.
Also, your functions are over-coupled. If all you want to fix is selectionSort, then you should be able to post that plus a main that calls it with some test data and displays the result, but no, your functions all call each other. Learn to decouple.
Also your variable names are awful.

Reading and writing to a file in c++

I am trying to write a triple vector to a file and then be able to read back into the data structure afterward. When I try to read the file back after its been saved the first fifty values come out correct but the rest of the values are garbage. I'd be really appreciative if someone could help me out here. Thanks a lot!
File declaration:
fstream memory_file("C:\\Users\\Amichai\\Pictures\\output.txt", ios::in | ios::out);
Save function:
void save_training_data(fstream &memory_file, vector<vector<vector<long double> > > &training_data)
{
int sizeI = training_data.size();
memory_file.write((const char *)&sizeI, sizeof(int));
for (int i=0; i < sizeI; i++)
{
int sizeJ = training_data[i].size();
memory_file.write((const char *)&sizeJ, sizeof(int));
for (int j=0; j < sizeJ; j++)
{
int sizeK = training_data[i][j].size();
memory_file.write((const char *)&sizeK, sizeof(int));
for (int k = 0; k < sizeK; k++)
{
int temp;
temp = (int)training_data[i][j][k];
memory_file.write((const char *)&temp, sizeof(int));
}
}
}
}
Read function:
void upload_memory(fstream &memory_file, vector<vector<vector<long double> > > &training_data)
{
memory_file.seekg(ios::beg);
int temp=0;
int sizeK, sizeJ, sizeI;
memory_file.read((char*)&sizeI, sizeof(int));
training_data.resize(sizeI);
for (int i=0; i < sizeI; i++)
{
memory_file.read((char*)&sizeJ, sizeof(int));
training_data[i].resize(sizeJ);
for (int j=0; j < sizeJ; j++)
{
memory_file.read((char*)&sizeK, sizeof(int));
training_data[i][j].resize(sizeK);
for (int k = 0; k < sizeK; k++)
{
memory_file.read((char*)&temp, sizeof(int));
training_data[i][j][k]=temp;
}
}
}
}
Since you're writing binary data (and apparently working under Windows) you really need to specify ios::binary when you open the fstream.
The problem is that you're writing the numerical values in binary form to a file interpreted as text by the stream processor. Either use a binary file (using ios::binary) or convert the numbers to strings before writing to file.
Check out the Boost.Serialization library at www.booost.org. It knows how to read and write STL collections to/from files. I don't know if it can handle nested containers, though.
You may also want to use Boost.Multiarray for your 3-dimensional data. If you're going to do matrix math on your data, then you might want to use Boost.uBlas.
As the other answers suggest using "ios::in | ios::out | ios::binary" instead of "ios::in | ios::out" which is correct, however I remember reading that the C++ stream specification while having the binary option was not designed for binary files at all. If using "ios::binary" doesn't help you would need to use the C function fopen(), fread(), fwrite(), and fclose() of stdio.h instead or, as another user suggests, the Boost::Serilization library.