4d mapping in C++ with tuple - c++

This is somewhat similar to this problem 4d mapping in C++? and one of my previous questions on maps in C++ Use a map with the map name defined by a string C++
I have a code that looks like this (that does not work and stops at the line giving input to the map):
#include <iostream>
#include <string>
#include <tuple>
#include <map>
#include <vector>
using namespace std;
int main()
{
map<string, //Volkswagen (car brand)
map<string, //series
map<int, //in this example 1
tuple<string, string>>>> mapMapMap;
string myCarmapMapMap = "Volkswagen";
int Number = 1;
mapMapMap[myCarmapMapMap]["3 series"][Number] = {90, 20};,
string Output;
Output.assign(get<0>(mapMapMap[myCarmapMapMap].find("3 series")->second));
cout << "\n" << "------------" << "\n" << Output << "\n"<< "------------" << "\n";
}
What I want to do is to assign two values to Volkswagen, 3 series, 1 and then be able to call it like:
Volkswagen -> 3 series -> 1 -> <0> (value 1).
This is the error message I get:
|19|error: expected primary-expression before ',' token|
I have also tried:
mapMapMap.insert({myCarmapMapMap, "3 series", Number, {"90", "20"}});
But it does not work either. How do I combine a 4d map with a tuple?

Change your assignment so it can actually form a tuple<string, string> (note the quotation signs on the right hand side):
mapMapMap[myCarmapMapMap]["3 series"][Number] = {"90", "20"};
Example
Also, remove the , at the end of the line.
Your query can, probably, be fixed by including the Number again, like:
string output = get<0>(mapMapMap[myCarmapMapMap].find("3 series")->second[Number]);

Related

C++ Need help sorting a 2D string array

I'm a little stuck with sorting a string Table[X][Y]. As tagged, Im using C++ and have to use standard libraries and make it for all C++ (not only C++ 11).
The size of the Table is fixed (i get the X reading how many lines a file has and the Y is fixed because thats the different "attributes" has each line).
When i create the Table, each part of it is obtained as Table[X][Y] = stringX.data(); from things previously read from a file and stored in strings. I have numbers in the first column (the one im going to use as sorting criteria), names, address, etc in the others.
The part where the Table is created is:
Table[i][0] = string1.data();
Table[i][1] = string2.data();
Table[i][2] = string3.data();
Table[i][3] = string4.data();
Table[i][4] = string5.data();
Where "i" is the current "iteration" of a while(fgets) that reads one line at a time from a file, does some operations and stores in those strings the "final values" of each part of the line read.
I have to sort that Table using the first column as criteria in decreasing order.
Lets imagine the Table is like this: Table[4][3]
20 | Jhon | 14th July
2 | Mary | 9th June
44 | Mark | 10th December
1 | Chris | 4th Feb
And i need the output to be this:
44 | Mark | 10th December
20 | Jhon | 14th July
2 | Mary | 9th June
1 | Chris | 4th Feb
I have been reading several questions and pages and they sort int/chars arrays or convert the array into vector and then work with them. Im trying to sort the string Table i have without converting anything (dunno if possible).
I dont know if i managed to explain the issue and the situation i have clear enough. Im not putting all the code i have because apart from the declaration of the string Table and the strings that are then placed as string.data in the Table, the rest of the code has nothing to do with the Table and the sorting process. The code opens the file, reads line by line, filters the info i need from some separators and special characters and places each of the "rankings criteria" to a string, then assigns a "ranking" after evaluating each of the criterias and giving a total score (which then is stored in "string1").
After all this is done, i create the string Table[x][y] and place the filtered and processed information in that Table one row at a time (because i assing this while reading each line from the file).
The only thing that remains is the sorting of the table from the best scored to the last and then create a file with the top 10.
I appreciate and thank in advance the time you took reading this and any tip, information, code or source from where i can read this that you could provide.
First, as mentioned in the comments, a variable length array is accomplished in C++ by using std::vector. The current syntax you're using
std::string Table[X][Y]
where either X or Y are runtime variables, is not legal C++. Given your example, a standard C++ declaration would be this:
std::vector<std::array<std::string, 3>> Table;
So let's assume that this is what you are going to use.
The next step is to sort the data based on the first column. That can be accomplished by utilizing the std::sort algorithm function, along with the appropriate predicate indicating that you are using the first column as the sorting criteria.
Here is a short example, using your data, of how this is all accomplished:
#include <vector>
#include <array>
#include <iostream>
#include <algorithm>
#include <string>
int main()
{
std::vector<std::array<std::string, 3>> Table;
// Set up the test data
Table.push_back({"20", "Jhon", "14th July"});
Table.push_back({"2", "Mary", "9th June"});
Table.push_back({"44", "Mark", "10th December"});
Table.push_back({"1", "Chris", "4th Feb"});
std::cout << "Before sort:\n\n";
for (auto& s : Table)
std::cout << s[0] << " | " << s[1] << " | " << s[2] << "\n";
std::cout << "\n\nAfter sort:\n\n";
// Sort the data using the first column of each `std::array` as the criteria
std::sort(Table.begin(), Table.end(), [&](auto& a1, auto& a2)
{ return std::stoi(a1[0]) > std::stoi(a2[0]); });
// Output the results:
for (auto& s : Table)
std::cout << s[0] << " | " << s[1] << " | " << s[2] << "\n";
}
Here is the final output:
Before sort:
20 | Jhon | 14th July
2 | Mary | 9th June
44 | Mark | 10th December
1 | Chris | 4th Feb
After sort:
44 | Mark | 10th December
20 | Jhon | 14th July
2 | Mary | 9th June
1 | Chris | 4th Feb
The output needs a little bit of formatting, but that's not important.
Remember, it is not important as to where the data comes from, whether it is from a file or hardcoded as the example above shows. However you populate the Table, that's up to you. The goal is to show you once populated, how to sort the data.
The first thing we did was create the Table and fill it in with the test data. Note that the vector has a push_back function to add entries to the vector.
Then the call to std::sort has a predicate function (the lambda), where the predicate is given two items, in this case it would be two std::array's by reference. Then the goal is to return if the first std::array (in this case, a1) should be placed before the second std::array (a2).
Note that we only care about the first column, so we only need to consider array[0] of each of those arrays, and compare them.
Also note that since array[0] is a std::string, we simply can't compare it lexicographically -- we need to convert the string to an int and compare the int value. That's the reason for the std::stoi call to convert to an integer.
The final thing about the sort predicate is that we want to have a descending sort. Thus the comparing operator to use is > instead of the "traditional" < (which would have sorted in a ascending manner).
Hopefully this explains what the code is doing.
Edit:
Since you are attempting to get this code to work in C++98, the easiest way to do that is
Change to std::vector<std::vector<std::string>> instead of std::vector<std::array<std::string, 3>>
Not use the brace-initialization that C++11 offers
Use a comparison function instead of a lambda.
Given that, here is the code for C++98:
#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
bool SortFirstColumn(const std::vector<std::string>& a1,
const std::vector<std::string>& a2)
{
return atoi(a1[0].c_str()) > atoi(a2[0].c_str());
}
int main()
{
std::vector<std::vector<std::string>> Table;
// Set up the test data
std::vector<std::string> vect(3);
vect[0] = "20";
vect[1] = "Jhon";
vect[2] = "14th July";
Table.push_back(vect);
vect[0] = "2";
vect[1] = "Mary";
vect[2] = "9th June";
Table.push_back(vect);
vect[0] = "44";
vect[1] = "Mark";
vect[2] = "10th December";
Table.push_back(vect);
vect[0] = "1";
vect[1] = "Chris";
vect[2] = "10th December";
Table.push_back(vect);
std::cout << "Before sort:\n\n";
for (size_t i = 0; i < Table.size(); ++i)
std::cout << Table[i][0] << " | " << Table[i][1] << " | " << Table[i][2] << "\n";
std::cout << "\n\nAfter sort:\n\n";
// Sort the data using the first column of each `std::vector<std::string>` as the criteria
std::sort(Table.begin(), Table.end(), SortFirstColumn);
// Output the results:
for (size_t i = 0; i < Table.size(); ++i)
std::cout << Table[i][0] << " | " << Table[i][1] << " | " << Table[i][2] << "\n";
}

Parsing date string to int using cpp

I was trying to solve a problem. The Problem is : There is given a date string like 21/9/2013. I have to convert this date into int. I have used stoi but it is just showed first two int 21.
I want to print 21 9 2013 to the console
So you don't really need three integers. You need three strings.
With these includes:
#include <string>
#include <sstream>
using namespace std;
You can parse a string like this:
string date = "21/9/2013";
into its components, like this:
stringstream stream(date);
string s;
while (std::getline(stream, s, '/') {
cout << s << " ";
}
cout << endl;
The above should print out: 21 9 2013
If you really want integers, the above shouldn't be too hard to modify. You can use stoi on each iteration of the while loop above.
What you want to do here is tokenize the string into three different substrings ("21", "9", and "2013"); then you can call stoi() on each substring and print out the integer stoi() returned for each one.
There are various ways to tokenize a string in C++; rather than choose one to repeat here, I'll just link to the StackOverflow question and answers on that topic.

C++ remove function moving characters to the left [duplicate]

This question already has answers here:
Difference between erase and remove
(7 answers)
Closed 2 years ago.
I recently tried a code mentioned somewhere on this site to remove blank spaces in a string. The answer suggested the function remove from the algorithm library (amazingly explained here: https://www.geeksforgeeks.org/stdremove-stdremove_if-c/) but it gives an unexpected output. It replaces all the blank spaces with some random numbers. Here is the code.
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
string a;
int b;
getline(cin, a);
remove(a.begin(), a.end(), ' ');
b = stoi(a);
cout << b << endl;
return 0;
}
If I input 14 546 32 for example it outputs 145463232. Oddly enough if I input 1 2 3 4 5 it outputs the correct thing: 12345.
Expected output, input:
I input any number with blank spaces in between some numbers.
It outputs the number without spaces.
I tried compiling it online with this compiler: https://www.onlinegdb.com/. It has the exact same output. Can anybody figure out what is wrong with the code. And also i need to turn the string into an integer to do some mathematical operations with the integer afterwards (that is why I use the stoi function). Thanks.
Interesting thing about std::remove is that it does not actually remove anything. =)
You will need to erase the character by yourself like this:
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
string a;
int b;
getline(cin, a);
a.erase(remove(a.begin(), a.end(), ' '), a.end());
b = stoi(a);
cout << b << endl;
return 0;
}
You can read more about Erase–remove here:
https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
std::remove removes the elements that compare equal to its argument by shifting the remaining elements using move-assignment. It doesn't resize the container after shifting those elements. In your case, since the objects are of type char, they are simply copied to the beginning of the array. So the end of your string stays the same.
When you remove spaces from the first number, and shift everything to left, you get this:
old string: 14 546 32
new string: 145463232
When you do the same in the second case:
old string: 1 2 3 4 5
new string: 12345 4 5
The only reason you get the correct result in the second one is the space in-between. First number in the string (12345) is converted to int and returned.
Note that std::remove also returns an iterator to the new end of the list. You could use that to resize the string.
auto end = remove(a.begin(), a.end(), ' ');
a.resize(end - a.begin());

How can I sort the following sequence of strings in c++?

So, I am solving a question which involves sorting a given sequence of proper strings composed of opening and closing brackets. An n parentheses sequence consists of n "("s and n ")"s.
A valid parentheses sequence is defined as the following:
You can find a way to repeat erasing adjacent pair of parentheses "()" until it becomes empty.
For example, "(())" is a valid parentheses, you can erase the pair on the 2nd and 3rd position and it becomes "()", then you can make it empty.
")()(" is not a valid parentheses. Now, I want to know how can I sort the generated sequence of parentheses of a given length such that those strings which have the maximum opening brackets come in beginning and if two strings have same number of opening brackets in beginning, then, on traversing both the strings, whichever has the first opening bracket will be printed first. For example, for n=3, the sorted sequence will be,
((())) // 3 opening in a row and hence first
(()()) // 2 opening (same as the one which is below this one) but has a opening bracket first
(())()
()(())
()()()
You can use the standard sorting algorithm, std::sort
The default (lexicographical) ordering will achieve exactly what you want.
I may be missing something but I think a straight sort will work. Its a bit like binary numbers except with '(' and ')' instead of 1s and 0s.
#include <random>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
std::vector<std::string> tests =
{
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
};
int main()
{
std::shuffle(tests.begin(), tests.end(),
std::default_random_engine(std::random_device{}()));
std::cout << "\nbefore:\n";
for(auto const& s: tests)
std::cout << s << '\n';
// normal sort
std::sort(tests.begin(), tests.end());
std::cout << "\nafter:\n";
for(auto const& s: tests)
std::cout << s << '\n';
}
Example Output:
before:
(()())
(())()
()()()
((()))
()(())
after:
((()))
(()())
(())()
()(())
()()()

Pulling info from a file into a map and need to overwrite duplicate values?

Hi so I have a homework assignment and have it all done except for the last requirement. We're pulling in data from a txt file and several of the box office values are 0. Instead of returning the first instance of 0, we are to return the last instance of 0. Here's a snippet of code:
long long worldBoxOffice = movie.getWorldBoxOffice();
movieMap.insert(pair<long long, Movie>(worldBoxOffice, movie));
So after inserting the pair into the map, what is it that I should be doing? Would it be overloading the [] operator? Kinda confused so any help is appreciated. I didn't post more code because I'm not looking for code, just a push in the right direction as to how to go about it. Thanks.
Note: we have to use maps, not allowed to use multi maps, etc.
Maybe I am misunderstanding but if you just use operator [] instead to assign to the map when you read in your data you will end up with the last 0 instance that you read in, like this trivial example:
#include <iostream>
#include <map>
int main()
{
std::map<int,int>
m ;
m[0] = 1 ;
std::cout << m[0] << std::endl ;
m[1] = 2 ;
m[0] = 3 ;
std::cout << m[0] << std::endl ;
}
As insert doesn't replace existing keys, you should not be using it in the first place. Nothing after such an (ineffective) insert will get your data back.
You can use the [] operator: movieMap[worldBoxOffice] = movie; or do the insertions in reverse order - read the file backwards.