How to split vector into subsets? - c++

I'm trying to split the vector into subsets based of the number of process I use in my application. I created the pseudo code but I really don't have any clue how can I output the subsets.
The problem:
Read a subset of the address records from residences.dat using
striping. For n processes, each process evaluates a unique subset of
records based on every nth record. The number of records in this
subset should be approximately #-of-residence-records /#-of-processes. Across all the parallel processes used no address should be omitted and none should be processed more than once. Also
note that only ONE record at a time should be stored in memory by any
process
My code:
std::vector<Residence> spliteResidenceDaata(vector<Residence> rs,int numProces = 0);
function body
std::vector<Residence> spliteResidenceDaata(vector<Residence> rs,int numProces)
{
std::vector<Residence> residenceSet;
//get the size of vector
int res_set_size = rs.size();
int sizrOfSubSet =res_set_size/numProces;
//output the arry subsite some "help here"
return residenceSet;
}
update
I came up with this pseudo code
1-take the number of line in .dat file rData
2- get the number of data you want to read for each process sizeofLine (rData.size()/numProc)
3- read the .dat file from line 0 to sizeofLine
4-output array

i haven't tested this code, but something along the lines of this should work - instead of having your function return one vector, have it return a vector of vectors, like this:
std::vector<std::vector<Residence>> split(std::vector<Residence rs, int num_procs)
this will allow you to split your original vector into num_procs number of vectors, and then push_back() each of those onto your return vector of vectors (kind of like a matrix).
std::vector<std::vector<Residence>> split(const std::vector<Residence> rs, const unsigned num_procs) {
unsigned j = 0; //position counter
std::vector<std::vector<Residence>> result; //resulting vector of vectors
for(unsigned i = 0; i < num_procs; ++i) { //for each process
std::vector<Residence> temp; //create a vector
for(; j < ((i + 1) * rs.size() / num_procs; ++j) //iterate
temp.push_back(rs[j]); //and populate temporary vector with a 1/num_procs section of original vector
result.push_back(temp); //and push that temporary vector into your result vector of vectors
}
for(; j < rs.size(); ++j) //finally, if the original vector is not divisible by num_procs
result[num_procs].push_back(rs[j]); //push the remainder of elements into the last vector
}
when you call the function, it will look something like this:
std::vector<std::vector<Residence>> vectors = split(original_vector, 4);
which will allow you to get subvectors like this:
vectors[0]; //first quarter
vectors[1]; //second
vectors[2]; //third
vectors[3]; //fourth + remainder

you need to read one record at time not pass the all subset as vector think you need this
while(!residenceFile.eof())
{
residenceFile >> res.x >>res.y;
if ( numLines % numProcs == rank)
{
//call the process
//populate_distancesVector(res,foodbankData);
analysis_range(populate_distancesVector(res,foodbankData),count);
}
++numLines;
}

Related

Pushing back a vector of strings into a 2D vector

I am currently working in C++, dealing with string vectors.
Let's say I have a 1D string vector called 'temp.' At each index of 'temp', there is a string containing three words/chars. Let's say that temp[0] = "Hello hi 3"
I have defined a function called 'splits' which takes in some string, and removes the whitespaces, and places the result in a string vector called 'res'. So, using the 'splits' function on temp[0] results in:
res[0] = hello
res[1] = hi
res[2] = 3
I would like to use the "splits" function on each string held in 'links,' and pass it into a 2d vector of strings called 'totalResults.' As I do not know the size of 'links' I know that I will need to dynamically allocate this 2D vector of strings.
So far I have:
vector<vector<string>> totalResults //dynamically allocated 2d vector of strings
vector<string> temp;
for (int i = 0; i<rows; i++)
{
for (int j = 0; j<cols; j++)
{
temp=splits(links[j])
totalResults[i][j].push_back(temp[0][j]));
//using splitting function on links[i], and pushing it into the 2d vector
}
}
In this example, I would like "hello" to go into totalResults[0][0], "hi" to go into totalResults[0][1], and "3" to go into totalResults[0][2].
In the second row of totalResults, I would like the same assignment to occur, but when 'splits' is used on 'links[1]'.
I have testing the 'splits' function in isolation, and it works as I expect it to, so I am assuming the error may be in how I am pushing back values into this 2d vector. I am testing the resulting 2D matrix, but nothing is printing... Are the values not actually being pushed in?
I appreciate any help/ideas!
Thank you! :)
Based on your description, links has cols elements, and you want to split each links[j] and add it to totalResults:
vector<vector<string>> totalResults(cols);
for (int j = 0; j < cols; j++)
{
totalResults[j] = splits(links[j]);
}

trying to load info from a vector containing classes into a two dimensional string vector

I use an input function I made to take info from a text file and input it into the private fields of a class let's call it student, each time a record is filled with the first row from the text input file I push_back the filled class in the vector students to end up with a vector containing classes which contain the data from the input file.
So now in order to be able to perform manipulations on this data I want to load it into a two dimensional string vector but I'm having a hard time implementing this. Below is how far I have gotten, I feel like at this point I'm running in a circle. Any help is appreciated.
The parameter passed (size) is how many rows there are in the text file which is checked prior to this function running.
void student::loadData(int size)
{
vector <vector<string> > tempVec(size);
string first, middle, last, addressNum, addressStreet,
phone, gender, email, emContactFirst, emContactLast,
ph, emPhone, ID, age;
//FIXME//
for (vector<student>::iterator it = students.begin(); it != students.end(); it++){
for (int i = 0; i < size; size++)
{
tempVec[size].push_back(it->getName());
tempVec[size].push_back(it->getId());
tempVec[size].push_back(it->getAge());
tempVec[size].push_back(it->getPhone());
tempVec[size].push_back(it->getAddress());
tempVec[size].push_back(it->getEmail());
tempVec[size].push_back(it->getEmPhone());
tempVec[size].push_back(it->getEmContact());
tempVec[size].push_back(it->gpa);
tempVec[size].push_back(it->honors);
tempVec[size].push_back(it->major);
it++;
}
}
//trying to output 2-dimensional array for debugging purpouses
//(trying to mimic what the output file would look like)
for (int i = 0; i < size; size++)
{
for (vector<string>::iterator z = tempVec[size].begin(); z != tempVec[size].end(); z++){
//**FIX ME**//;
}
}
}
There are several problems here. Don't increment size in the for loops, you want to increment i.
tempVec[size] is outside the bounds of the vector. You want tempVec[i] instead.
Don't increment it inside the inner for loop.

how to add element into the nested vector

Hello sorry for the stupid question but I am very beginner in c++. I cannot describe the problem well because of my bad English. I'll add my code here that i have tried so far.
vector< vector<string> >allData;
int main(){
vector<string>test;
for(int i = 0; i<allData.size(); i++){
test = allData[i];
}
int id;
cout<<"enter Id"<<endl;
cin>>id;
if (id == test[2]){
string desc;
cout<<"enter ur description"<<endl;
cin>>description;
allData.push_back(description);
} else {
cout<<"there is no data with the id u have entered"<<endl;
}
}
Above code is just an example code. Lets say that there are 2 vectors inside the vector named allData, so when i enter the ID of a first vector i can add description into the vector which i have chosen by choosing it by its Id. Somehow i cannot do that thing like choosing the first or second vector by inputing their ids then add more datas into chosen 1. So please someone tell me what should i do. I know that above code is incomplete and awful but as i said before i am very beginner in c++
You can add values into nested vector just like a normal vector. So you could do allData[i].push_back(description) or even allData[i][j] = description to overwrite an existing value. However you are trying to push a string into allData which does not contain strings but rather Vectors of strings.
Additionally your first for loop runs through allData and saves each to test, overwriting test each time. When the loop is done test will simply contain the last element of allData. Thus your for loop is the equivalent of doing test = allData.back()
Well, if you need to access your child vectors directly, you need to declare your vector saying how many child vectors it has (without this, you have segmentation fault when trying to access it ie. allData[0] will be unitialised).
Let's say you have 2, so they will be allData[0] and allData[1], just like a normal array.
std::vector<std::vector<std::string>> allData (2);
allData[0].push_back("string0a");
allData[0].push_back("string0b");
allData[1].push_back("string1");
for(auto & a : allData[0])
std::cout << a << "\n";
Of course, you can add vectors dinamically too.
std::vector<std::vector<std::string>> allData;
std::vector<std::string> child0;
child0.push_back("string0");
allData.push_back(child0);
And to check if the id the user input is valid, you can do
if(id >= 0 && id < allData.size()) {
....
Your variable all_data is a vector of vectors representing rows and columns. You can create a scratch vector for a row, push_back() data on that scratch vector, then push_back() that scratch vector onto all_data like so:
#include <vector>
int main() {
std::vector<std::vector<int>> all_data;
for (int ii = 0; ii < 10; ii++) {
std::vector<int> row_data;
for (int jj = 0; jj < 10; jj++) {
row_data.push_back(ii * jj);
}
all_data.push_back(row_data);
}
return (0);
}

Assigning a structure to another structure results in garbage

The two structures used in my code, one is nested
struct Class
{
std::string name;
int units;
char grade;
};
struct Student
{
std::string name;
int id;
int num;
double gpa;
Class classes[20];
};
I am trying to figure out a way to sort the structures within the all_students[100] array in order of their ID's in ascending order. My thought was, to start counting at position 1 and then compare that to the previous element. If it was smaller than the previous element then I would have a temporary array of type Student to equate it to, then it would be a simple matter of switching them places within the all_students array. However, when I print the results, one of the elements ends up being garbage numbers, and not in order. This is for an intermediate C++ class in University and we are not allowed to use pointers or vectors since he has not taught us this yet. Anything not clear feel free to ask me.
The function to sort the structures based on ID
void sort_id(Student all_students[100], const int SIZE)
{
Student temporary[1];
int counter = 1;
while (counter < SIZE + 1)
{
if (all_students[counter].id < all_students[counter - 1].id)
{
temporary[0] = all_students[counter];
all_students[counter] = all_students[counter - 1];
all_students[counter - 1] = temporary[0];
counter = 1;
}
counter++;
}
display(all_students, SIZE);
}
There are a few things wrong with your code:
You don't need to create an array of size 1 to use as a temporary variable.
Your counter will range from 1 to 100, you will go out of bounds: the indices of an array of size 100 range from 0 to 99.
The following solution uses insertion sort to sort the array of students, it provides a faster alternative to your sorting algorithm. Note that insertion sort is only good for sufficiently small or nearly sorted arrays.
void sort_id(Student* all_students, int size)
{
Student temporary;
int i = 1;
while(i < size) // Read my note below.
{
temporary = all_students[i];
int j = i - 1;
while(j >= 0 && temporary.id < all_students[j].id)
{
all_students[j+1] = all_students[j]
j--;
}
all_students[j+1] = temporary;
i++;
}
display(all_students, size);
}
Note: the outer while-loop can also be done with a for-loop like this:
for(int i = 1; i < size; i++)
{
// rest of the code ...
}
Usually, a for-loop is used when you know beforehand how many iterations will be done. In this case, we know the outer loop will iterate from 0 to size - 1. The inner loop is a while-loop because we don't know when it will stop.
Your array of Students ranges from 0, 99. Counter is allowed to go from 1 to 100.
I'm assuming SIZE is 100 (in which case, you probably should have the array count also be SIZE instead of hard-coding in 100, if that wasn't just an artifact of typing the example for us).
You can do the while loop either way, either
while(counter < SIZE)
and start counter on 0, or
while (counter < SIZE+1)
and start counter on 1, but if you do the latter, you need to subtract 1 from your array subscripts. I believe that's why the norm (based on my observations) is to start at 0.
EDIT: I wasn't the downvoter! Also, just another quick comment, there's really no reason to have your temporary be an array. Just have
Student temporary;
I overlooked the fact that I was allowing the loop to access one more element than the array actually held. That's why I was getting garbage because the loop was accessing data that didn't exist.
I fixed this by changing while (counter < SIZE + 1)
to: while (counter < SIZE )
Then to fix the second problem which was about sorting, I needed to make sure that the loop started again from the beginning after a switch, in case it needed to switch again with a lower element. So I wrote continue; after counter = 1

Selective Infinite Loop in Making a Tournament Tree

I want to write a program that randomly generates a tournament tree using only the number of challengers. I read into another such problem, but the answer described how ranks would take part and seeding the players, which went a little over head.
The problem I am facing is that my algorithm produces an infinite loop for values between 1 and 4 inclusively. For all values otherwise, the program runs as desired.
My approach was to take in an array of strings for the competitors' names. Then, I would iterate over each position and randomly select a competitor's name to take that spot. Because I am swapping the names, I have to check for duplicates in the array. I believe this is where my code is experiencing issues.
Here is the snippet that actually determines the tree
for(int i = 0; i < no_players;) {
int index = rand() % ((no_players - i) + i);
// randomly choose an element from the remainder
string temp = players[index];
bool unique = true;
// check all the elements before the current position
for(int j = 0; j < i; j++) {
// if the element is already there, it is not unique
if(players[j] == temp)
unique = false;
}
// only if the element is unique, perform the swap
if(unique) {
players[index] = players[i];
players[i] = temp;
i++;
}
}
Any help is much appreciated!