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

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

Related

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.

Doing a scenario problem in C++ and am unsure of how to proceed with boolean and if-loops

**This is a translation, very hastily written. If you need any clarification, just comment.
The question given is:
We live in a world with too much garbage. We have found a way to compress the garbage, but it can only be done in a specific way, or else the garbage will explode. The garbage has to be laid out in a line, and it can only be compressed with its neighbor, and only if its neighbor has the same value as it.
The first input is int N, and it represents the amount of garbage in the row. The second input is t, and it must have an input of as many characters as the value in N. If the whole thing is able to be compressed until there's only 1 garbage (t) left, then the output will be "YES".
We've figured out that as long as either N == 1, or all inputs in t (all the characters) are the same, the output will be YES.
Example inputs/outputs:
Input:
2
1 1
Output:
YES
Or
Input:
3
1 2 1
Output:
NO
Or
Input:
1
5
Output:
YES
Here's what we've got so far:
#include <iostream>
#include <string>
using namespace std;
int N;
string t;
bool allCharactersSame(string s)
{
int n = s.length();
for (int i = 1; i < n; i++) {
if (s[i] != s[0])
return false;
}
return true;
}
int main()
{
cin>>N;
cin >> t;
if (N == 1)
{
cout << "YES";
}
else if (allCharactersSame(t))
{
cout <<"YES";
}
else
{
cout<<"NO";
}
}
The problem with this is that it outputs YES no matter what, and we think it's because it takes the whitespace of the input into consideration. If we don't include spaces, it works fine. BUT the question dictates that we Have To have spaces separating our inputs. So, we're stumped. Any suggestions?
(I can't comment, therefore I write this as an answer.)
There is some other problem than you think, because the code in the question works as it should. When I gave it input "5 11111" it said "YES" when I gave it "5 12345" it said "NO".
Kai's first comment is slightly weird, when determining whether all characters in a string are the same it is sufficient to compare each of them to the first one, just as you do it in your allCharactersSame() method.
I'd suggest you add some checks on the provided input; the program should probably notice if given N doesn't match given strings' length and it should probably notice when the given string doesn't consist of numbers. As it is now, e.g. input "3 a" says "YES".

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:
((()))
(()())
(())()
()(())
()()()

Unexpected behaviour of getline() with ifstream

To simplify, I'm trying to read the content of a CSV-file using the ifstream class and its getline() member function. Here is this CSV-file:
1,2,3
4,5,6
And the code:
#include <iostream>
#include <typeinfo>
#include <fstream>
using namespace std;
int main() {
char csvLoc[] = "/the_CSV_file_localization/";
ifstream csvFile;
csvFile.open(csvLoc, ifstream::in);
char pStock[5]; //we use a 5-char array just to get rid of unexpected
//size problems, even though each number is of size 1
int i =1; //this will be helpful for the diagnostic
while(csvFile.eof() == 0) {
csvFile.getline(pStock,5,',');
cout << "Iteration number " << i << endl;
cout << *pStock<<endl;
i++;
}
return 0;
}
I'm expecting all the numbers to be read, since getline is suppose to take what is written since the last reading, and to stop when encountering ',' or '\n'.
But it appears that it reads everything well, EXCEPT '4', i.e. the first number of the second line (cf. console):
Iteration number 1
1
Iteration number 2
2
Iteration number 3
3
Iteration number 4
5
Iteration number 5
6
Thus my question: what makes this '4' after (I guess) the '\n' so specific that getline doesn't even try to take it into account ?
(Thank you !)
You are reading comma separated values so in sequence you read: 1, 2, 3\n4, 5, 6.
You then print the first character of the array each time: i.e. 1, 2, 3, 5, 6.
What were you expecting?
Incidentally, your check for eof is in the wrong place. You should check whether the getline call succeeds. In your particular case it doesn't currently make a difference because getline reads something and triggers EOF all in one action but in general it might fail without reading anything and your current loop would still process pStock as if it had been repopulated successfully.
More generally something like this would be better:
while (csvFile.getline(pStock,5,',')) {
cout << "Iteration number " << i << endl;
cout << *pStock<<endl;
i++;
}
AFAIK if you use the terminator parameter, getline() reads until it finds the delimiter. Which means that in your case, it has read
3\n4
into the array pSock, but you only print the first character, so you get 3 only.
the problem with your code is that getline, when a delimiter is specified, ',' in your case, uses it and ignores the default delimiter '\n'. If you want to scan that file, you can use a tokenization function.

C++ string manipulation / input

This is for homework! But I need help anyway. The assignment is to input a sentence then output the number of words, and the number of occurrences of each letter. The output must have the letters in alphabetical order. So far, I've been able to count the number of words and get all the letters to lower case so that I'll be able to keep count of them. My question is how to actually keep count of the letters.
Example of output:
I say Hi.
3 words
1 a
1 h
2 i
1 s
1 y
Here's the code that I have so far:
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main()
{
int letters[26];
char letter;
int word = 0;
cout << "Please enter a sentence: "<< endl;
do
{
cin.get(letter);
if(isspace(letter))
word++;
letter = tolower(letter);
cout << letter;
}
while (letter != '\n');
cout << "The number of words = " << word << endl;
return 0;
}
Should I input directly into a C-string? or will that mess up the word count?
If you're allowed to use STL, use std::map for mapping letters to counters. It will additionally sort the letters.
Otherwise, treat chars as indexes in an array of counters and increment them.
My question is how to actually keep
count of the letters
It's fairly straight forward. Simply create an array of 26 integers, (one for each letter), and initialize it to zero.
int letters[26] = { 0 }; // Initialize array to zero
Each value in the array corresponds to a count of a particular letter. Array index 0 refers to 'a', array index 1 refers to 'b', and so on. Then, everytime you encounter a letter, increment the appropriate value in the array. You can use the character 'a' (ASCII value 97) as a starting offset. So, given the variable char letter; you would do:
++letters[tolower(letter) - 'a'];
But always make sure that before you increment the appropriate value in the array, you check that isalpha(letter) && islower(letter) to make sure that your letter is in the range of lowercase a-z; otherwise you will access an index beyond the bounds of the array. You can also test for this condition by saying if (letter >= 'a' && letter <= 'z').
Hint: tolower(letter)-'a' is:
0 if letter is a
1 if letter is b
...
Hm, just few points to make your home task more useful to you (and your code more correct):
Think what happens if you have file with several spaces in a row (word counting).
Think how to be more correct with 'letters' (check for isalpha() at least). Also isalpha() could be key for simpler counting with fixed array [256] (this might be even the best solution as for performance vs std::map usage, check std::map documentation anyway).
Think about more effective file input. At least line at once.