How to apply tolower to a string vector? - c++

Since tolower only works for individual characters, how would I use tolower for a string vector? I know I would have to go through each individual character of each item, however I am unsure how to access the individual characters within each item.
eg:-
string vector[Apple, Banana].
vector[0] is Apple but I want the character not the whole string. Thanks in advance!

#include<iostream>
#include<vector>
#include<string>
using namespace std;
int main() {
vector<string> fruits;
fruits.push_back("Apple");
fruits.push_back("Banana");
for(int i = 0; i<fruits.size(); i++){
for(auto& c : fruits[i])
{
c = tolower(c);
}
cout << fruits[i] << endl;
}
}
Basically we loop through the character in the vector and make it tolower.

std::transform can help you here to apply tolower to each character in each string inside in your vector:
#include <iostream>
#include <algorithm> // std::transform
#include <string>
#include <vector>
int main()
{
//Your vector of strings
std::vector<std::string> fruits = { "Apple", "Banana" };
//Loop through vector
for (auto &fruit : fruits)
{
//Apply tolower to each character of string
std::transform(fruit.begin(), fruit.end(), fruit.begin(),
[](unsigned char c) { return std::tolower(c); });
}
for (auto const& fruit : fruits)
std::cout << fruit << ' ';
}
Demo
As #AlanBirtles suggested you could apply std::transform for the outer loop too. Then it becomes like this:
std::transform(fruits.begin(), fruits.end(), fruits.begin(),
[](std::string &fruit)
{
std::transform(fruit.begin(), fruit.end(), fruit.begin(),
[](unsigned char c) { return std::tolower(c); });
return fruit;
});
Demo

Related

How to capitalize the first letter of each name in an array?

Here is the question:
Create a function that takes an array of names and returns an array where only the first letter of each name is capitalized.
example
capMe(["mavis", "senaida", "letty"]) ➞ ["Mavis", "Senaida", "Letty"]
And the code I wrote to answer this question:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void capme(vector<string> name)
{
char ch;
for(int i = 0; i < name[i].size(); i++)
{
putchar(toupper(name[i][0]));
cout << name[i] << endl;
}
}
int main()
{
vector <string> name = {"mavis", "senaida", "letty"};
capme(name);
return 0;
}
As you can see, it prints "Mmavis", "Ssenaida", "Lletty", which is wrong. Can you guys help me in answering this question as I don't know how?
To change the input argument, we have two choice: make the argument mutable reference, or add a return type, here I choose the first one.
putchar can be used to print only one character, it recommended to use cout to print a string, possible solutions:
with traditional loop: capme
with range for-loop since c++11 : capme2
with stl algorithm transform: capme3
Don't forget to check if the string element is empty, or you may crash while accessing the first character.
To obey the single-responsibility principle (SRP), it's better to print the string vector out of the capme function.
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void capme(vector<string>& name) {
for (int i = 0; i < name[i].size(); i++) {
if (name[i].empty()) continue;
name[i][0] = toupper(name[i][0]);
}
}
void capme2(vector<string>& names) {
for (auto& name : names) {
if (name.empty()) continue;
name[0] = toupper(name[0]);
}
}
void capme3(vector<string>& names) {
std::transform(names.begin(), names.end(), names.begin(), [](auto& s) {
return s.empty() ? s : (s[0] = toupper(s[0]), s);
});
}
Online demo
You have used the wrong function. What you need is a replacement and not a prepend. Try using std::string::operator[] to access the first element of the words in the vector. This is how I would write this code:
std::vector<string> capitaliseInitLetter(std::vector<string> vec) {
for (auto& word : vec) {
word[0] -= 32; //add a check to see if the letter is already capital
}
return vec;
}
The above code is just an example which assumes that the input is valid. You'll have to add checks and exception handling for invalid inputs on your own. (Hint: Take a look at #prehistoricpenguin's answer)
You are calling putchar() which writes a character to standard output, and in this case is printing the first letter of each string in name as uppercase, then you are writing the entire string to standard output immediately after.
Additionally, your function does not meet the requirements you stated above saying it should return an array where the strings have the first letter capitalized.
What you could do is change the signature of capme() to return a std::vector<std::string>, and perhaps utilize the for_each() function to handle changing the first letter of each string in your vector then return it.
For reference:
#include <vector>
#include <string>
#include <algorithm>
#include <cctype>
std::vector<std::string> capme(std::vector<std::string> name)
{
std::for_each(name.begin(), name.end(), [](std::string &s) {
s[0] = toupper(s[0]);
});
return name;
}
Or as kesarling suggested, a simple for each loop:
std::vector<std::string> capme(std::vector<std::string> name)
{
for (auto& s : name) {
s[0] = toupper(s[0]);
}
return name;
}

How to make a 2d vector from input string?

I got this problem in one of the coding questions in my university exam where I knew the answer but couldn't follow as I didn't know how to parse the string and convert it into a 2d vector.
So I have got a 2d vector in the form of a string
"[[1,4], [5,7], [4,1], [8,9]]"
I want to convert this string into a vector<vector<int>>
EDIT
Maybe I wasn't clear the last time and there's one thing I missed. The string is
"[[1,4], [5,7], [4,1], [8,9]]"
I want this string to be in the form of a 2d vector. So, let's say I have a vector vec defined as vector<vector<int>> vec. Then vec[0]={1,4}, vec[1]={5,7}, vec[2]={4,1}, vec[3]={8,9}. Below is what I did and it shows incorrect output
#include<iostream>
#include<sstream>
#include<vector>
using namespace std;
int main()
{
string str="[[1,4], [5,7], [4,1], [8,9]]";
stringstream ss(str);
vector<vector<int>> vec;
string temp;
while(ss>>temp){
cout<<temp<<endl;
vector<int> t;
int x,y;
stringstream ss2(temp);
while(ss2>>x>>y)
{
t.push_back(x);
t.push_back(y);
}
vec.push_back(t);
}
}
The generic answer is to write a recursive descent parser (look it up). It's a fancy way of saying that you write a function for each of the non-terminals (vector2, vector, int) then you usually look at just the first byte to figure out to do. In this case your grammar might be:
vector2 = "[" vector (, " " vector) "]"
vector = "[" int (, number) "]"
number = 0 | 1 [0-9]
Then you implement number, vector and vector_vector similar to how #StPiere showed you previously.
I usually use c, and I found this generic function signature to be a useful start:
char *parse_something(const char *s, something *v)
where s is the string you are parsing and the return value is what the next thing is you want to parse.
Here is quick implementation Godbolt:
Note: This answer does not handle cases where integers have more than one digit. It is not generic or easily extensible, but as this is a homework question, you can understand and improve the code.
#include <string>
#include <vector>
#include <istream>
#include <sstream>
#include <cctype>
#include <iostream>
#include <iterator>
int main()
{
std::string input{"[[1,4], [5,7], [4,1], [8,9]]"};
std::stringstream ss{input};
auto it = std::istream_iterator<char>{ss};
std::vector<std::vector<int>> output;
std::vector<int> inner;
// Loop through the string, one character at a time
while (it != std::istream_iterator<char>{})
{
++it;
// If we encounter a digit, push it into the inner vector
if (std::isdigit(*it))
{
// Dirty hack to convert char to integer (assumes ASCII)
inner.push_back(*it - 48);
}
// If you encounter a ']' char, then push inner vector into the outer vector
// and then clear the inner vector
// For the final ']', the inner vector will be size 0, ignore this case
if (*it == ']')
{
if (inner.size() != 0)
{
output.push_back(inner);
}
inner.clear();
}
}
}
#include <iostream>
#include <vector>
using namespace std;
template <typename Range>
void print_range(const Range& r)
{
for (const auto& e : r)
cout << e << " ";
cout << endl;
}
int main()
{
vector<int> v;
vector<vector<int>> vv;
char c;
int cnt = 0;
while (cin >> c)
{
if (c == ',' || c == ' ' || c == '\n')
{
continue;
}
if (c == '[')
{
++cnt;
v.clear();
continue;
}
if (c == ']')
{
--cnt;
if (cnt == 0)
break;
vv.push_back(v);
v.clear();
continue;
}
cin.unget();
int x;
if (cin >> x)
v.push_back(x);
}
for (const auto& vec : vv)
print_range(vec);
}

How to remove consonants from a string? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
Here is my code:
#include <iostream>
#include <string>
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
while(n--)
{
string str;
char a[] = {'a','e','i','o','u','A','E','I','O','U'};
getline(cin, str);
for(int i=0 ;i<str.length(); i++)
{
for(int j=0; j<10; j++)
{
if(str[i]==a[j])
{
cout << str[i];
}
}
}
cout << "\n";
}
return 0;
}
Test cases are :
HmlMqPhBfaVokhR
wdTSFuI
IvfHOSNv
I am not removing anything but I am printing only vowels. But, some test cases didn't pass. Maybe this code doesn't work on multiple test cases.
Try this for proper console in :
int main()
{
int n;
std::cin >> n;
std::cin.ignore(); // fix
/* remaining code */
return 0;
}
> To find the vowels in a string
On way of finding the vowels in a string is using a std::binary_search each character of the given string in a vowel table.
Make a sorted array of char s of all vowels(i.e. vowels array).
For each char of the input string, std::binary_search in the
vowels array.
If std::binary_search returns true(meaning the char is an vowel), print the char of the string.
Following is the example code! (See live online)
#include <iostream>
#include <string>
#include <algorithm> // std::for_each, std::binary_search, std::sort
#include <array> // std::array
int main()
{
std::array<char, 10> a{ 'a','e','i','o','u','A','E','I','O','U' };
std::sort(a.begin(), a.end()); // need sorted array for std::binary_search
const std::string str{ "HmlMqPhBfaVokhR wdTSFuI IvfHOSNv" };
std::for_each(str.cbegin(), str.cend(), [&](const char str_char)
{
if (std::binary_search(a.cbegin(), a.cend(), str_char))
std::cout << str_char << " ";
});
return 0;
}
Output:
a o u I I O
> To remove the vowels from a string
Use erase-remove idiom as follows(till c++17†).
Make a sorted array of char s of all vowels(i.e. vowels array).
Using std::remove_if, collect the iterators pointing to the characters, which are vowels. A lambda function can be used as the predicate for std::remove_if, where the std::binary_search is used to check the char in the string exists in the vowels array.
Using std::string::erase, erase all the collected characters(i.e. vowels) from the string.
Following is an example code! (See live online)
#include <iostream>
#include <string>
#include <algorithm> // std::sort, std::binary_search, std::remove_if
#include <array> // std::array
int main()
{
std::array<char, 10> a{ 'a','e','i','o','u','A','E','I','O','U' };
std::sort(a.begin(), a.end()); // need sorted array for std::binary_search
std::string str{ "Hello World" };
// lambda(predicate) to check the `char` in the string exist in vowels array
const auto predicate = [&a](const char str_char) -> bool {
return std::binary_search(a.cbegin(), a.cend(), str_char);
};
// collect the vowels
const auto vowelsToRemove = std::remove_if(str.begin(), str.end(), predicate);
// erase the collected vowels using std::string::erase
str.erase(vowelsToRemove, str.end());
std::cout << str << "\n";
return 0;
}
Output:
Hll Wrld
† Since c++20, one can use std::erase_if for this, which would be less error prone than the the above one. (See online live using GCC 9.2)
#include <iostream>
#include <string> // std::string, std::erase_if
#include <array> // std::array
int main()
{
std::array<char, 10> a{ 'a','e','i','o','u','A','E','I','O','U' };
std::sort(a.begin(), a.end()); // need sorted array for std::binary_search
std::string str{ "Hello World" };
// lambda(predicate) to check the `char` in the string exist in vowels array
const auto predicate = [&a](const char str_char) -> bool {
return std::binary_search(a.cbegin(), a.cend(), str_char);
};
std::erase_if(str, predicate); // simply erase
std::cout << str << "\n";
return 0;
}
> To remove the consonants from a string
To remove the consonants from the given string, in the above predicate negate the result of std::binary_search. (See live online)
const auto predicate = [&a](const char str_char) -> bool {
return !std::binary_search(a.cbegin(), a.cend(), str_char);
// ^^ --> negate the return
};
As side notes,
Avoid the #include<bits/stdc++.h> Read more: Why should I not #include <bits/stdc++.h>?
Do not practice with using namespace std; Read more: Why is "using namespace std;" considered bad practice?
Apart from the std::getline problem already answered:
for(int i=0 ;i<str.length(); i++)
{
for(int j=0; j<10; j++)
{
if(str[i] == a[j])
{
// this is the one you do NOT want to print...
// cout<<str[i];
// skip instead:
goto SKIP;
}
}
std::cout << str[i]; // output the one NOT skipped...
SKIP: (void)0;
}
OK, don't want to start any discussion about usage of goto, there are many ways to avoid it, e. g. by packing the inner for loop into a separate (inline) function. You can have it easier, though, as there already exists such a function; code gets even easier with a range-based for loop:
for(auto c : str)
{
if(!strchr("aeiouAEIOU", c))
{
std::cout << c;
}
}
strchr (from cstring) returns a pointer to the first character in the string equal to the reference character - or nullptr if not found...
To really remove the vowels from the string in a modern C++ way, consider this:
str.erase(std::remove_if(
str.begin(), str.end(),
[](char c) { return strchr("aeiouAEIOU", c) != nullptr; }
), str.end());
Your code probably should looks like (please see comments inline):
#include <iostream>
#include <string>
using namespace std;
int main() {
string vowels = "aeiouAEIOU";
int n;
cin>>n; // assume this stands for line count
while(n-- >= 0)
{
string str, result;
getline(cin, str);
for(int i=0 ;i<str.length(); i++)
{
if (vowels.find(str[i]) != std::string::npos)
result += str[i]; // add character to result if it is not consonant
}
cout<<result<<"\n"; // print result
}
return 0;
}

Check if a vector of strings is a substring in one of elements

I have a vector of strings like
a1 = ["arp", "live", "strong"]
a2 = ["lively", "alive", "harp", "sharp", "armstrong"]
How would I check if armstrong is a substring of strong in a1. using C++
I would do two for loops and check if a string is a substring in a2, but I want an efficient approach.
std::vector<std::string> inArray(std::vector<std::string> &array1, std::vector<std::string> &array2)
{
vector<string> result;
for (string &s : array1)
{
for (string &d : array2)
{
if (s.find(d) != string::npos)
{
cout << d << endl;
}
}
}
return result;
}
int main() {
vector<string> a = { "arp", "live", "strong" };
vector<string> b = { "lively", "alive", "harp", "sharp", "armstrong" };
vector<string> result = inArray(a, b);
}
Given two arrays of strings a1 and a2 return a sorted array r in lexicographical order of the strings of a1 which are substrings of strings of a2.
Example 1:
a1 = ["arp", "live", "strong"]
a2 = ["lively", "alive", "harp", "sharp", "armstrong"]
returns ["arp", "live", "strong"]
First: Use names for the variables and functions that make it easy to identify the purpose
Second: A vector will not magically fill itself.
Third: You are currently searching for the full strings within the substrings (see first)
Fourth: Pass the value by const reference if you don't plan on modifying it.
Fifth: According to your expected answer you don't want duplicates. I would suggest using std::set for this purpose as it doesn't allow duplicates.
#include <vector>
#include <set>
#include <string>
#include <iostream>
using std::set;
using std::vector;
using std::string;
using std::cout;
set<string> getMatchingSubstrings(const vector<string> &subStrings, const vector<string> &fullStrings)
{
set<string> result;
for (const string &fullString : fullStrings)
{
for (const string &subString : subStrings)
{
if (fullString.find(subString) != string::npos)
{
result.insert(subString);
}
}
}
return result;
}
int main() {
vector<string> a = { "arp", "live", "strong" };
vector<string> b = { "lively", "alive", "harp", "sharp", "armstrong" };
set<string> result = getMatchingSubstrings(a, b);
}
A slightly faster approach might be remove the already found substrings from the initial list so you don't have to check for these twice. In this case the result won't be sorted, so if you need to sort again this might not be the best choice.
#include <vector>
#include <string>
#include <iostream>
using std::vector;
using std::string;
using std::cout;
std::vector<std::string> getMatchingSubstrings(const std::vector<std::string> &subStrings, const std::vector<std::string> &fullStrings)
{
vector<string> unmatchedSubStrings = subStrings;
vector<string> matchedSubStrings;
for (const string &fullString : fullStrings)
{
if (unmatchedSubStrings.empty()) break;
for (auto subStringIter = unmatchedSubStrings.begin(); subStringIter != unmatchedSubStrings.end();)
{
const string& subString = *subStringIter;
if (fullString.find(subString) != string::npos)
{
matchedSubStrings.push_back(subString);
subStringIter = unmatchedSubStrings.erase(subStringIter);
}
else
{
++subStringIter;
}
}
}
return matchedSubStrings;
}
int main() {
vector<string> a = { "arp", "live", "strong" };
vector<string> b = { "lively", "alive", "harp", "sharp", "armstrong" };
vector<string> result = getMatchingSubstrings(a, b);
}

Change String Array to tolower

In my program I have a text file that is read into an array that tokenizes each word. I need it this way so that I can compare the words to the words found in my Binary Tree. Issue is... some duplicates of words are not formatted the same way (one is uppercase and one is lowercase) and I need them to be so they can be found in my Binary Tree.
So my question is: How do I change my whole array to lowercase?
Here is what I tried so far:
#include <iostream>
#include "Binary_SearchTree.h"
#include "Node.h"
#include <string>
#include <fstream>
#include <sstream>
using namespace std;
const int SIZE = 100;
string myArray[SIZE];
int main() {
// first constructor will be used since it is empty
Binary_SearchTree<string> *tree = new Binary_SearchTree<string>();
string token, lines;
ifstream file("hashtags.txt");
while (getline(file, lines)){
tree -> insertNode(lines);
}
// Convert all strings in myArray to all-lower
myArray = tolower(myArray);
// tokenize tweet into an array to search
ifstream tweet1("exampleTweet.txt");
if(tweet1.is_open())
{
while (getline(tweet1, token)){
for(int i = 0; i < SIZE; ++i)
{
tweet1 >> myArray[i];
}
}
tweet1.close();
}
With C++11 and later, you can downcase an array of strings like this:
#include <algorithm>
#include <cctype>
#include <string>
std::string myArray[23];
// ...
for (std::string & s : myArray)
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c) { return std::tolower(c); });
Alternatively:
for (std::string & s : myArray)
std::for_each(s.begin(), s.end(), [](char & c) {
c = std::tolower(static_cast<unsigned char>(c)); });
Or even:
for (std::string & s : myArray)
for (char & c : s)
c = std::tolower(static_cast<unsigned char>(c));
If you only have C++98 support, use the following loops:
for (std::size_t i = 0; i != 23; ++i)
{
std::string & s = myArray[i];
for (std::string::iterator it = s.begin(), e = s.end(); it != e; ++it)
{
*it = std::tolower(static_cast<unsigned char>(*it));
}
}
You get the idea.
Don't forget to convert the character to unsigned char, since that's what std::tolower expects. (See this question for a discussion.) Many C I/O functions are expressed in terms of unsigned char-converted-to-int, since usually an int is big enough to represent all values of an unsigned char plus additional out-of-band information, and char and unsigned char are roundtrip convertible both ways as well as layout-compatible.