how to add element into the nested vector - c++

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);
}

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]);
}

2D Vector - Remove Rows by search

I'm quite new to vector and need some additional help with regards to vector manipulation.
I've currently created a global StringArray Vector that is populated by string values from a text file.
typedef std::vector<std::string> StringArray;
std::vector<StringArray> array1;
I've created a function called "Remove" which takes the input from the user and will eventually compare the input against the first value in the array to see whether it's a match. If it is, the entire row will then deleted and all elements beneath the deleted row will be "shuffled up" a position to fill the game.
The populated array looks like this:
Test1 Test2 Test3
Cat1 Cat2 Cat3
Dog1 Dog2 Dog3
And the remove function looks like this:
void remove()
{
string input;
cout << "Enter the search criteria";
cin >> input;
I know that I will need a loop to iterate through the array and compare each element with the input value and check whether it's a match.
I think this will look like:
for (int i = 0; i < array1.size(); i++)
{
for (int j = 0; j < array1[i].size(); j++)
{
if (array1[i] = input)
**//Remove row code goes here**
}
}
But that's as far as I understand. I'm not really sure A) if that loop is correct and B) how I would go about deleting the entire row (not just the element found). Would I need to copy across the array1 to a temp vector, missing out the specified row, and then copying back across to the array1?
I ultimately want the user to input "Cat1" for example, and then my array1 to end up being:
Test1 Test2 Test3
Dog1 Dog2 Dog3
All help is appreciated. Thank you.
So your loop is almost there. You're correct in using one index i to loop through the outer vector and then using another index j to loop through the inner vectors. You need to use j in order to get a string to compare to the input. Also, you need to use == inside your if statement for comparison.
for (int i = 0; i < array1.size(); i++)
{
for (int j = 0; j < array1[i].size(); j++)
{
if (array1[i][j] == input)
**//Remove row code goes here**
}
}
Then, removing a row is the same as removing any vector element, i.e. calling array1.erase(array1.begin() + i); (see How do I erase an element from std::vector<> by index?)
Use std::list<StringArray> array1;
Erasing an item from an std::vector is less efficient as it has to move all the proceeding data.
The list object will allow you to remove an item (a row) from the list without needing to move the remaining rows up. It is a linked list, so it won't allow random access using a [ ] operator.
You can use explicit loops, but you can also use already implemented loops available in the standard library.
void removeTarget(std::vector<StringArray>& data,
const std::string& target) {
data.erase(
std::remove_if(data.begin(), data.end(),
[&](const StringArray& x) {
return std::find(x.begin(), x.end(), target) != x.end();
}),
data.end());
}
std::find implements a loop to search for an element in a sequence (what you need to see if there is a match) and std::remove_if implements a loop to "filter out" elements that match a specific rule.
Before C++11 standard algorithms were basically unusable because there was no easy way to specify custom code parameters (e.g. comparison functions) and you had to code them separately in the exact form needed by the algorithm.
With C++11 lambdas however now algorithms are more usable and you're not forced to create (and give a reasonable name to) an extra global class just to implement a custom rule of matching.

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.

Faster way to sort an array of structs c++

I have a struct called count declared called count with two things in it, an int called frequency and a string called word. To simplify, my program takes in a book as a text file and I count how many times each word appears. I have an array of structs and I have my program to where it will count each time a word appears and now I want a faster way to sort the array by top frequency than the way I have below. I used the bubble sorting algorithm below but it is taking my code way too long to run using this method. Any other suggestions or help would be welcome!! I have looked up sort from the algorithm library but don't understand how I would use it here. I am new to c++ so lots of explanation on how to use sort would help a lot.
void sortArray(struct count array[],int size)
{
int cur_pos = 0;
string the_word;
bool flag= true;
for(int i=0; i<(size); i++)
{
flag = false;
for(int j=0; j< (size); j++)
{
if((array[j+1].frequency)>(array[j].frequency))
{
cur_pos = array[j].frequency;
the_word = array[j].word;
array[j].frequency = array[j+1].frequency;
array[j].word = array[j+1].word;
array[j+1].frequency = cur_pos;
array[j+1].word = the_word;
flag = true;
}
}
}
};
You just need to define operator less for your structures,
and use std::sort, see example:
http://en.wikipedia.org/wiki/Sort_%28C%2B%2B%29
After you created a pair of for the data set, you can use std::map as container and insert the pairs into it. If you want to sort according to frequency define std:map as follows
std::map myMap;
myMap.insert(std::make_pair(frequency,word));
std::map is internally using a binary tree so you will get a sorted data when you retrieve it.

Trying to fill a 2d array of structures in C++

As above, I'm trying to create and then fill an array of structures with some starting data to then write to/read from.
I'm still writing the cache simulator as per my previous question:
Any way to get rid of the null character at the end of an istream get?
Here's how I'm making the array:
struct cacheline
{
string data;
string tag;
bool valid;
bool dirty;
};
cacheline **AllocateDynamicArray( int nRows, int nCols)
{
cacheline **dynamicArray;
dynamicArray = new cacheline*[nRows];
for( int i = 0 ; i < nRows ; i++ )
dynamicArray[i] = new cacheline [nCols];
return dynamicArray;
}
I'm calling this from main:
cacheline **cache = AllocateDynamicArray(nooflines,noofways);
It seems to create the array ok, but when I try to fill it I get memory errors, here's how I'm trying to do it:
int fillcache(cacheline **cache, int cachesize, int cachelinelength, int ways)
{
for (int j = 0; j < ways; j++)
{
for (int i = 0; i < cachesize/(cachelinelength*4); i++)
{
cache[i][ways].data = "EMPTY";
cache[i][ways].tag = "";
cache[i][ways].valid = 0;
cache[i][ways].dirty = 0;
}
}
return(1);
}
Calling it with:
fillcache(cache, cachesize, cachelinelength, noofways);
Now, this is the first time I've really tried to use dynamic arrays, so it's entirely possible I'm doing that completely wrong, let alone when trying to make it 2d, any ideas would be greatly appreciated :)
Also, is there an easier way to do write to/read from the array? At the moment (I think) I'm having to pass lots of variables to and from functions, including the array (or a pointer to the array?) each time which doesn't seem efficient?
Something else I'm unsure of, when I pass the array (pointer?) and edit the array, when I go back out of the function, will the array still be edited?
Thanks
Edit:
Just noticed a monumentally stupid error, it should ofcourse be:
cache[i][j].data = "EMPTY";
You should find your happiness. You just need the time to check it out (:
The way to happiness