Class template implementation with multiple vectors - c++

I'm creating a program that reads in a data file into a vector and then shows the minimum and maximum information for the vector. I also have to use a class template for finding the minimum and maximum. I'm wondering if there is a way I can reference ANY vector without having to specifically label the two vectors I want to use. In my code below, I have to state vector v1 to get my template to do the minimum and maximum. Is it possible to make this template for any vector?
//Nicholas Stafford
//COP2535.0M1
//Read in text file into multiple vectors and display maximum and minimum integers/strings.
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <algorithm>
using namespace std;
//Template code area
template <class T>
T min(vector<T> v1)
{
T lowest = v1[0];
for (int k = 1; k < 10; k++)
{
if (v1[k] < lowest)
lowest = v1[k];
}
return lowest;
}
template <class T>
T max(vector<T> v1)
{
T highest = v1[0];
for (int k = 1; k < 10; k++)
{
if (v1[k] > highest)
highest = v1[k];
}
return highest;
}
int main() {
//Number of items in the file
const int size = 10;
//Vector and file stream declaration
ifstream inFile;
string j; //String for words in data file
vector<int> v1(size); //Vector for integers
vector<string> v2(size); //Vector for strings
//Open data file
inFile.open("minmax.txt");
//Loop to place values into vector
if (inFile)
{
for (int i = 0; i < size; i++)
{
inFile >> v1[i];
v1.push_back(v1[i]); //Add element to vector
}
cout << "The minimum number in the vector is " << min(v1) << endl;
cout << "The maximum number in the vector is " << max(v1) << endl;
}
else
{
cout << "The file could not be opened." << endl;
}
}

You're having a simple misunderstanding. Just because the function parameter to your min and max is v1 doesn't mean the only thing you can call it with is something called v1. Actually, it will be a local copy of the vector passed in, locally named v1.
#include <vector>
#include <iostream>
template<typename T>
size_t sizeit(std::vector<T> v) // try changing to v1, v2 and vx
{
return v.size(); // change to match
}
int main() {
std::vector<int> v1 { 1, 2, 3, 4, 5 };
std::vector<float> v2 { 1., 2., 3. };
std::cout << "v1 size = " << sizeit(v1) << "\n";
std::cout << "v2 size = " << sizeit(v2) << "\n";
}
Live demo: http://ideone.com/cK13bR

Related

How to print certain elements from vector?

I am trying to print out whatever is necessary from my program. What it does is it takes a long list from a text file and sort it based on first choice and GPA and put it into a vector. I manage to sort by First choice and GPA however how can I remove whatever output that isn't necessary?
This is an example of my Txt File (The sequence of each line is 1st choice, 2nd choice, 3rd choice, GPA, Name):
CC,DR,TP,3.8,AlexKong
SN,SM,TP,4,MarcusTan
DR,TP,SC,3.6,AstaGoodwin
SC,TP,DR,2.8,MalcumYeo
SN,SM,TP,3.7,DavidLim
SN,SM,TP,3.2,SebastianHo
SC,TP,DR,4,PranjitSingh
DR,TP,SC,3.7,JacobMa
and so on...
This is my output now (it is a long vector):
TP,DR,SC,4,SitiZakariah
TP,DR,SC,3.9,MuttuSami
TP,DR,SC,3.5,SabrinaEster
TP,DR,SC,3,KarimIlham
TP,DR,SC,3,AndryHritik
SN,SM,TP,4,MarcusTan
SN,SM,TP,3.8,MarcusOng
SN,SM,TP,3.7,DavidLim
SN,SM,TP,3.4,MollyLau
SN,SM,TP,3.2,SebastianHo
SN,SM,TP,3.2,NurAfiqah
SN,SM,TP,2.4,TanXiWei
SC,TP,DR,4,SallyYeo
SC,TP,DR,4,PranjitSingh
SC,TP,DR,3.6,RanjitSing
SC,TP,DR,2.8,MalcumYeo
SC,TP,DR,2.8,AbdulHalim
SC,TP,DR,2.7,AlifAziz
DR,TP,SC,3.9,SitiAliyah
DR,TP,SC,3.9,LindaChan
DR,TP,SC,3.8,SohLeeHoon
DR,TP,SC,3.7,PrithikaSari
DR,TP,SC,3.7,NurAzizah
DR,TP,SC,3.7,JacobMa
DR,TP,SC,3.6,AstaGoodwin
CC,DR,TP,3.9,MuruArun
CC,DR,TP,3.8,AlexKong
CC,DR,TP,3.7,DamianKoh
CC,DR,TP,3.3,MattWiliiams
CC,DR,TP,3.3,IrfanMuhaimin
And this is the output that I need (Basically students with CC as their 1st choice without displaying the 3 options):
3.9,MuruArun
3.8,AlexKong
3.7,DamianKoh
3.3,MattWiliiams
3.3,IrfanMuhaimin
This is my program.
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;
struct greater
{
template<class T>
bool operator()(T const &a, T const &b) const { return a > b; }
};
void main()
{
vector<string> v;
int p = 0;
ifstream File;
File.open("DSA.txt");
if (!File.is_open()) return;
string First;
cout << "Round 1:\n";
while (File >> First)
{
v.push_back(First);
p++;
}
for (int i = 0; i < v.size(); i++)
{
sort(v.begin(), v.end(), greater());
cout << v[i] << endl;
}
}
your last for loop:
for (int i = 0; i < v.size(); i++)
{
sort(v.begin(), v.end(), greater());
cout << v[i].substr(9) << endl;
}
EDIT:
If you want to only display ones with CC as 1st choice you can add if statement to your loop:
for (int i = 0; i < v.size(); i++)
{
if (v[i].substr(0,2) != "CC") continue;
cout << v[i].substr(9) << endl;
}
Also, I noticed another problem in your code. You should not sort the vector at every iteration. You should do it only once before the loop:
sort(v.begin(), v.end(), greater());
for (int i = 0; i < v.size(); i++)
{
if (v[i].substr(0,2) != "CC") continue;
cout << v[i].substr(9) << endl;
}
as I propose in the comment,
since the data is well defined as a structure, you can interpret semantically each row and filter according to that: here is what am talking about
int main()
{
std::vector<std::string> v;
std::string r = "CC,DR,TP,3.9,MuruArun";
std::string delimiter = ",";
std::string token = r.substr(0, r.find(delimiter));
if(token == ??)// compare to what ever you want
{
v.emplace_back(r);
}
cout << "token: " << token << endl;
cout << v.size() << endl;
return 0;
}

Separating multiple inputs from a file into even or odd

I need to take 200 randomizes numbers from a file, separate them into even and odd, and make them show up from lowest to highest in their even or odd parts.
I got the code for making it into even and odd from here but the original way had 10 instead of 200 and made the user input the numbers.
I reworked it into this but I get a repeat of the same number then an error that reads Exception thrown: write access violation with a mark near the odd[oddcnt++] = arr[i];
My code so far
#include <iostream>
#include <fstream>
using namespace std;
class Random
{
private:
int x, arr[200], even[200], odd[200], evncnt = 0, oddcnt = 0, i;
public:
void readFile();
};
void Random::readFile()
{
fstream File("Random.txt");
if (File.is_open())
{
while(File >> x)
{
for (i = 0; i < 200; i++)
{
arr[i] = x;
}
for (i = 0; i < 200; i++)
{
if (arr[i] % 2 == 0)
{
even[evncnt++] = arr[i];
}
else
{
odd[oddcnt++] = arr[i];
}
}
cout << "\n The even numbers are: ";
for (i = 0; i < evncnt; i++)
{
cout << even[i] << "";
}
cout << "\n The odd numbers are: ";
for (i = 0; i < oddcnt; i++)
{
cout << odd[i] << "";
}
}
File.close();
}
}
int main()
{
Random file;
file.readFile();
system("pause");
return 0;
}
Your loops are all wrong. This is how it should look
i = 0;
while (file >> x)
{
arr[i] = x;
i++;
}
for (i = 0; i < 200; i++)
{
if (arr[i]%2==0)
...
}
If you put one loop inside another (like you did) then the inner loop executes fully every time the outer loop executes once. That's not what you want (in this case).
The answer is given already by John. So everything OK.
Additionally, I would like to show you the power of modern C++. Especially with using algorithms. You can write very elegant solutions.
Thers is no loop and only vey few variables.
You will of course not copy and paste it, because you will not understand it fully. But it should give you an idea how such a problem could be analysed, then designed, and then coded.
#include <iostream>
#include <fstream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <string>
class Random {
std::vector<int> values{};
public:
void readFile(const std::string& fileName);
void printOdds();
void printEvens();
};
void Random::readFile(const std::string& fileName) {
// Open file and check, if it could be opened
if (std::ifstream inputFileStream(fileName); inputFileStream) {
// Clear old content in our class
values.clear();
// Copy the contents from the vile into our vector
std::copy(std::istream_iterator<int>(inputFileStream), {}, std::back_inserter(values));
// sort the values
std::sort(values.begin(), values.end());
}
else { // File could not be opened
std::cerr << "\n*** Error: File could not be opened: " << fileName << "\n\n";
}
}
// Copy all odd values to std::cout
void Random::printOdds() {
std::copy_if(values.begin(), values.end(), std::ostream_iterator<int>(std::cout, " "), [](const int i) { return (i % 2) != 0; });
std::cout << "\n\n";
}
// Copy all even values to std::cout
void Random::printEvens() {
std::copy_if(values.begin(), values.end(), std::ostream_iterator<int>(std::cout, " "), [](const int i) { return (i % 2) == 0; });
std::cout << "\n\n";
}
// Driver code
int main() {
Random r;
r.readFile("r:\\random.txt");
r.printEvens();
r.printOdds();
return 0;
}

Display a table after reading in dimensions and table contents from a text file

I am currently working on a project that displays a table after reading the contents and dimensions of the table from a text file.
The contents of puzzle.txt:
5 5
ferac
asdvb
mfkgt
opemd
welsr
I want my program to read the left number and store it in the variable numRow, and the right number in numCol, then read the letters into the puzzle array. However, when the dimension numbers print, they print as 0 0 instead of 5 5, and the puzzle array only outputs empty box characters.
#include <iostream>
#include <map>
#include <fstream>
#include <cstring>
#include <string>
using namespace std;
char puzzle [numRow][numCol];
void initializePuzzle() {
string storeInput;
int numRow, numCol;
cout << "What is the name of the file?" << endl;
getline(cin, storeInput);
ifstream inFile (storeInput);
inFile.open(storeInput.c_str());
for (int c = 0; c < sizeof(storeInput); c++) {
if (c == 0) {
inFile >> numRow >> numCol;
cout << numRow << ' ' << numCol << endl;
}
}
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
inFile >> puzzle[i][j];
}
}
}
void displayPuzzle() {
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
cout << puzzle[i][j];
}
cout << endl;
}
}
int main() {
initializePuzzle();
displayPuzzle();
return 0;
}
You can do this just by using the C++ Standard Library. Try this: (See about std::copy(), std::array and std::vector...)
#include <iostream> // For std::cout, std::endl, etc.
#include <fstream> // For std::ifstream
#include <vector> // For std::vector
#include <iterator> // For std::ostream_iterator
int main() {
std::string file_src;
// Ask for file name...
std::cout << "What is the name of the file? " << std::endl;
std::getline(std::cin, file_src);
// Declare the file stream...
std::fstream reader(file_src);
// Terminate the program with value '1' in case of failure when reading file...
if (reader.fail()) return 1;
// Declaring necessary varibles...
unsigned num_row, num_column;
std::string temporary;
/* Extracting 'num_row' and 'num_column' and declaring a 'std::vector' (which are
better than dynamic arrays in numerous ways) with the dimensions... */
reader >> num_row >> num_column;
std::vector<std::vector<char>> puzzle(num_row, std::vector<char>(num_column));
// Iterating over each line and copying the string where required...
for (auto i = 0; std::getline(reader, temporary, '\n') && i < num_row; i++)
if (!temporary.empty())
std::copy(temporary.begin(), temporary.end(), puzzle[i].begin());
else --i;
// Close the stream...
reader.close();
// Print the resulting vector...
for (auto & elem : puzzle) {
std::copy(elem.begin(), elem.end(), std::ostream_iterator<char>(std::cout, " "));
std::cout << std::endl;
}
return 0;
}
Example:
Input:
puzzle.txt
Output:
f e r a c
a s d v b
m f k g t
o p e m d
w e l s r

Cache locality with unique_ptr

I have a vector of custom classes (std::string just for example).
The vector is large and I iterate through often, so I rely on cache locality.
I also have one raw pointer which points at one of the vector elements.
Now is the trick:
The vector is sorted from time to time, so the raw pointer loose the actual pointed element value, and will point to some random element value.
Here is an example to illustrate the same:
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <memory>
using namespace std;
int main()
{
vector<string> v = {"9","3", "8", "7", "6", "5", "1", "4", "2"};
string* rs = &v[7]; //point to the 7th element
for (size_t i = 0; i < v.size(); ++i)
cerr << v[i];
cerr << endl;
cerr << "Referenced string: " << rs->c_str() << endl;
cerr << "Sort ..." << endl;
sort(v.begin(), v.end(), [](const string& a, const string& b)
{
if (a < b)
return true;
else
return false;
}
);
for (size_t i = 0; i < v.size(); ++i)
cerr << v[i];
cerr << endl;
cerr << "Referenced string: " << rs->c_str() << endl;
cin.get();
return 0;
}
Output:
938765142
Referenced string before sort : 4
Sort ...
123456789
Referenced string after sort : 8
Since I wish the rs pointer to keep pointing to the 7th element value (which is 4) even after the sort, I came up with the following solution (vector of pointers):
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <memory>
using namespace std;
int main()
{
vector<unique_ptr<string>> v;
v.resize(9);
v[0] = make_unique<string>("9");
v[1] = make_unique<string>("3");
v[2] = make_unique<string>("8");
v[3] = make_unique<string>("7");
v[4] = make_unique<string>("6");
v[5] = make_unique<string>("5");
v[6] = make_unique<string>("1");
v[7] = make_unique<string>("4");
v[8] = make_unique<string>("2");
string* rs = v[7].get();
for (size_t i = 0; i < v.size(); ++i)
cerr << v[i]->c_str();
cerr << endl;
cerr << "Referenced string before sort: " << rs->c_str() << endl;
cerr << "Sort ..." << endl;
sort(v.begin(), v.end(), [](const unique_ptr<string>& a, const unique_ptr<string>& b)
{
if (*a < *b)
return true;
else
return false;
}
);
for (size_t i = 0; i < v.size(); ++i)
cerr << v[i]->c_str();
cerr << endl;
cerr << "Referenced string after sort: " << rs->c_str() << endl;
cin.get();
return 0;
}
Output:
938765142
Referenced string before sort: 4
Sort ...
123456789
Referenced string after sort: 4
While this latter solution works, there is a price: I have lost the cache locality of my vector, since I store pointers in it, rather than the actual objects.
Is there a way to maintain cache locality (e.g.: store my actual objects in the vector), and somehow manage to rs pointer to keep track where its pointed value wander around due to the sorts?
Or from the other perspective, is there a way to achieve cache locality with the vector of pointers?
Solution from Pubby, thanks!:
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <memory>
using namespace std;
int main()
{
vector<string> data = { "d","e", "f", "g", "i", "b", "c", "a", "h" };
vector<int> indexes = {0,1,2,3,4,5,6,7,8};
int si = 6;
for (size_t i = 0; i < indexes.size(); ++i)
cerr << indexes[i];
cerr << endl;
for (size_t i = 0; i < indexes.size(); ++i)
cerr << data[indexes[i]];
cerr << endl;
cerr << "Referenced string before sort: " << data[si] << endl;
cerr << "Sort ..." << endl;
sort(indexes.begin(), indexes.end(), [&](const int a, const int b)
{
return data[a] < data[b];
}
);
for (size_t i = 0; i < indexes.size(); ++i)
cerr << indexes[i];
cerr << endl;
for (size_t i = 0; i < indexes.size(); ++i)
cerr << data[indexes[i]];
cerr << endl;
cerr << "Referenced string after sort: " << data[si] << endl;
cin.get();
return 0;
}
You can increase locality by storing the strings in a vector which doesn't change, and then store a vector of pointers/indexes to these strings.
Like this:
vector<string> data = {"9","3", "8", "7", "6", "5", "1", "4", "2"};
vector<unsigned> indexes(data.size());
std::iota(indexes.begin(), indexes.end(), 0u);
To sort your data you'd sort indexes using a custom comparator function which retrieves the values from data and compares them. Remember: indexes can change, but data should not!
sort(indexes.begin(), indexes.end(), [&](unsigned a, unsigned b)
{
return data[a] < data[b];
});
Just an idea: Instead of storing std::string in the vector, just append the character arrays of each string to a std::vector<char>.
This packs the strings closely together in memory, improving locality even better than std::string with small string optimization. It will also give better results if the strings exceed the max. size for small string optimization.
For sorting, store index and size of each string in a 2nd vector similar to Pubbys suggestion.
Of course this only works if the string length doesn't need to change dynamically. Otherwise you would have to rebuild the vector<char>.
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <string_view>
using namespace std;
using IndexAndSize = pair<size_t,size_t>;
void push_and_index( vector<char>& v, vector<IndexAndSize>& vi, string_view s )
{
vi.emplace_back( v.size(), s.size() );
v.insert( end(v), begin(s), end(s) );
}
string_view make_string_view( vector<char> const& v, IndexAndSize is )
{
return { v.data() + is.first, is.second };
}
int main()
{
vector<char> v;
vector<IndexAndSize> vi;
push_and_index( v, vi, "foo" );
push_and_index( v, vi, "bar" );
push_and_index( v, vi, "foobar" );
push_and_index( v, vi, "barfoo" );
sort( begin(vi), end(vi), [&]( IndexAndSize a, IndexAndSize b )
{
return make_string_view( v, a ) < make_string_view( v, b );
});
for( IndexAndSize is : vi )
{
cout << make_string_view( v, is ) << endl;
}
}
Live demo on Coliru.
Note: C++17's string_view is used only to help with the sorting and output, it's not crucial for this idea.

Novice C++, seeking help in array division

#include <iostream>
#include <valarray>
using namespace std;
// to get new card number
int main ()
{
int i;
int array[5]= {10,2,6,34,51};
valarray<int> v[5];
int v %= 13;
for (int i=0; i<5 ; i++) {
cout << v[i]%=13 << " ";
}
}
hello, my goal is to get the array to perform a modulus division by number 13.
I've search and try a few different way but I can't figure out a way to make it work.....
Thank you...
Some of the problems with your code:
valarray does not have the same notation as normal arrays: valarray<int> v[5]; declares 5 different valarray objects and puts them in a C-style array. The notation you are looking for is valarray<int> v(10);
Get rid of the int v %= 13; line: this redefines v (an array) as an integer.
Use v[i]=(array[i]%13); for the calculation, what you have doesn't make sense.
Then output cout << v[i] << " ";
Also, you aren't really using any of the features of valarray, so it may make more sense just to use one single array, like:
#include <iostream>
using namespace std;
// to get new card number
int main ()
{
int array[5]= {10,2,6,34,51};
for (int i=0; i<5 ; i++) {
array[i]%=13;
cout << array[i] << " ";
}
}
Edit: by the way, the cool thing about valarray here is that you can apply the same function to every value at once. Like this:
#include <iostream>
#include <valarray>
using namespace std;
int main() {
valarray<int> v(10);
for (int i=0;i<10;++i) {
v[i]=i*i; //Fill the array with 0,1,4,9,16,... as an example
}
v%=13; //This applies the modulo 13 on the whole array at once.
for (int i=0;i<10;++i) {
cout << v[i] << endl;
}
}
Seems you want something like...
int array[5]= {10,2,6,34,51};
int v[5];
for (int i = 0; i < 5; ++i)
v[i] = array[i] % 13;
for (int i = 0; i < 5; ++i)
std::cout << v[i] << " ";
std::cout << '\n';