Finding the total number of repeat strings in a string C++ -- without maps - c++

My program has to find the total number of repeated strings in a string. I cannot use maps or built in string functions other than length()
Example : string input = "Hello hello Hello"
Hello : 2
I am hitting a roadblock with separating the strings by the spaces and reading them. I can't figure out what to write to make that happen.
What I want to do is create a temp string to compare to the next string and if they are equal to store it in a vector and then read from the vector at the end.
What function could I use to do that?
Here is my code below :
#include<iostream>
#include<string>
#include<vector>
using namespace std;
vector <string> mystring;
int numberString(string const&in)
{
int total = 0;
char temp;
for (int i = 0; i < in.length(); i++)
{
temp = in[i];
if (temp == ' ')
total++;
}
total++;
return total;
}
void findRepeats(string const &in)
{
int numberOfStrings = numberString(in);
int asciiArray[256];
for (int i = 0; i < 256; i++)
asciiArray[i] = 0;
int counter = 0;
string temp = "blank";
while (numberOfStrings != counter)
{
temp = in;
}
}
int main()
{
string input;
cout << "Enter a string : ";
getline(cin, input);
findRepeats(input);
return 0;
}

The straightforward way to count substrings in a whitespace-separated string is to insert them into a map and and track the occurrence count:
std::string input = "Hello hello Hello";
std::istringstream iss(input);
std::map<std::string, size_t> m;
std::string temp;
while(iss >> temp)
{
auto it = m.find(temp);
if(it != std::end(m))
{
++(it->second);
}
else
{
m.insert(std::make_pair(temp, 0));
}
}
//display counts as:
for(auto it = std::begin(m); it != std::end(m); ++it)
{
std::cout<<"string \""<<it->first<<"\" was found "<<it->second<<" times"<<std::endl;
}
The code is untested.

The following code finds duplicate words as long as all words are seperated by a single space:
#include <string>
#include <map>
#include <sstream>
#include <iostream>
using namespace std;
int main()
{
string input = "Hello hello hello";
map<string, int> wordCount;
for (string::size_type p = 0; p < input.size(); )
{
const auto p2 = input.find_first_of(' ', p);
const auto word = input.substr(p, (p == string::npos) ? string::npos : (p2 - p));
++wordCount[word];
if (p2 == string::npos)
break;
p = p2 + 1;
}
for (const auto& it : wordCount)
if (it.second > 1)
std::cout << it.first << " " << it.second << std::endl;
return 0;
}
Be aware that this code does not only find consecutive duplicates. So "a b a" outputs 'a 2'.
The line ++wordCount[word] increments the counter for the word or initializes it to 1 if 'word' is not already found in the map (This is working because the template initializes the value with int() which is guaranteed to initialize to zero)
At the end you get a map with an entry for every unique word (first=Word, second=count)
If you would like to count only consecutive duplicates this piece of code may help you:
#include <string>
#include <map>
#include <sstream>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
string input = "Hello hello hello Hello";
vector<pair<string, int>> wordCount;
for (string::size_type p = 0; p < input.size(); )
{
const auto p2 = input.find_first_of(' ', p);
const auto word = input.substr(p, (p == string::npos) ? string::npos : (p2 - p));
if (wordCount.empty() || wordCount.back().first != word)
wordCount.push_back(make_pair(word, 1));
else
++wordCount.back().second;
if (p2 == string::npos)
break;
p = p2 + 1;
}
for (const auto& it : wordCount)
if (it.second > 1)
std::cout << it.first << " " << it.second << std::endl;
return 0;
}
This code does not use a map because a single word can have different counts depending on its location ("a a b a a a" would output "a 2" and "a 3")
Both examples scan the string word by word with ' ' as the delimiter. You could specify multiple delimiters in find_first_of if you would like to split your string by tab or dot. (input.find_first_of(" \t.", p))

Related

Why is it that my code is only showing the last element in the array even though It should be showing the element with the most amount of characters

#include <iostream>
#include <vector>
#include <ctime>
using namespace std;
vector<string> createvector() {
vector<string> words;
string names;
cout << "Please enter 5 different words: " << endl;
for (int i = 0; i < 5; i++) {
cin >> names;
words.push_back(names);
}
return (words);
}
void mostchar(vector<string> words) {
string w1 = words[0];
string largestword;
for (int i = 1; i < 5; i++) {
if (words[i] > w1) {
largestword = words[i];
}
}
cout << "The largest word is: " << largestword;
}
int main()
{
vector<string> words;
string names;
words = createvector();
mostchar(words);
}
I do not understand why it's picking the last element or the second to last element every time. Right I've tried to change for(int i = 1; i < 5; i++) but it makes no difference to what I do.
For starters you are comparing strings in the lexicographical order.
if (words[i] > w1) {
Secondly you always comparing with the word in the first element of the array
if (words[i] > w1) {
and the variable w1 is not being changed within the loop. So any last element in the vector that is greater than w1 will be assigned to the variable largestword.
Using the for loop the function can look the following way
void mostchar( const std::vector<std::string> &words )
{
size_t largestword = 0;
for ( size_t i = 1; i < words.size(); i++ )
{
if ( words[largestword].size() < words[i].size() )
{
largestword = i;
}
}
if ( largestword != words.size() )
{
std::cout << "The largest word is: " << words[largestword] << '\n';
}
}
Pay attention to that in general case the user can pass to the function an empty vector. You must check such a possibility within the function.
Bear in mind that there is standard algorithm std::max_element that can be used instead of manually written for loop.
For example
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
void mostchar( const std::vector<std::string> &words )
{
auto largestword = std::max_element( std::begin( words ), std::end( words ),
[]( const auto &a, const auto &b )
{
return a.size() < b.size();
} );
if ( largestword != std::end( words ) )
{
std::cout << "The largest word is: " << *largestword << '\n';
}
}
There are a couple issues here:
1: You should use something like .length() to compare "length"
2: You are comparing the next word in the array to words[0] every time.
EDIT: To further explain this, there is an assignment of string w1 = words[0];. w1 is then used in the if in the for loop here:
string w1 = words[0];
string largestword;
for (int i = 1; i < 5; i++) {
if (words[i] > w1) {
largestword = words[i];
}
}
resulting in the value of words[0] being the value repeatedly compared in the loop.
Adjust the comparison line to if (words[i].length() > largestword.length()) and that solves both problems. You can elminate w1 entirely this way as well.
#include <iostream>
#include <vector>
#include <ctime>
using namespace std;
vector<string> createvector() {
vector<string> words;
string names;
cout << "Please enter 5 different words: " << endl;
for (int i = 0; i < 5; i++) {
cin >> names;
words.push_back(names);
}
return (words);
}
void mostchar(vector<string> words) {
string largestword;
for (int i = 0; i < 5; i++) {
if (words[i].length() > largestword.length()) {
largestword = words[i];
}
}
cout << "The largest word is: " << largestword;
}
int main()
{
vector<string> words;
string names;
words = createvector();
mostchar(words);
}

Getting "Exited with return code -11(SIGSEGV)" when attempting to run my code

#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<string> separate(string str){
string build = "";
vector<string> temp;
for(int i = 0;i < str.size(); i++){
if(str[i] != ' '){
build += str[i];
} else if(str[i] == ' '){
temp.push_back(build);
build = "";
}
}
return temp;
}
int main() {
int count;
string sentence;
vector<int> numTimes;
getline(cin, sentence);
vector<string> words = separate(sentence);
for(int i = 0; i < words.size(); i++){
for(int j = 0; j < words.size(); i++){
if(words[i] == words[j]){
count++;
}
}
numTimes.push_back(count);
}
for(int k = 0; k < words.size(); k++){
cout << words[k] << " - " << numTimes[k] << endl;
}
return 0;
}
The code is supposed to receive a string, separate it into the individual words, place those words into a vector and finally output the number of times the word occurs in the sentence. However when running my code, I get a message saying that the program was exited with code -11. I have looked a bit online but do not fully understand what this means or where it is occurring in my code.
Changed signed counter variables (i, j) to unsigned (size_t) as you compare the two. In separate(..) changed if-else-if to just if-else, and fixed the loop per #user4581301 to use the right loop variable. Also fixed last word not being added. Minor reformat to use tab/8 space for indent.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<string> separate(string str) {
string build = "";
vector<string> temp;
for(size_t i = 0; i < str.size(); i++) {
if(str[i] == ' ') {
temp.push_back(build);
build = "";
} else {
build += str[i];
}
}
if(build.size()) {
temp.push_back(build);
}
return temp;
}
int main() {
int count = 0;
string sentence;
vector<int> numTimes;
getline(cin, sentence);
vector<string> words = separate(sentence);
for(size_t i = 0; i < words.size(); i++) {
for(size_t j = 0; j < words.size(); j++) {
if(words[i] == words[j]) {
count++;
}
}
numTimes.push_back(count);
}
for(size_t k = 0; k < words.size(); k++) {
cout << words[k] << " - " << numTimes[k] << endl;
}
return 0;
}
This seems to fix the segfault which answers question posed.
You haven't provided sample input and output but the counts clearly seems wrong. What do you mean with sentence? There is no notion of English sentences ending with '.' or whatever:
./a.out
a bc d
a - 1
bc - 2
d - 3
./a.out
a a b
a - 2
a - 4
b - 5
Suggest you work on that and open new question if you need further help.
#Allan Wind is right, but to offer an alternate solution using the C++17 standard.
Iterating
Rather than use indexes, let's use a more modern for loop.
for (const char &ch : s)
Rather than:
for (size_t i = 0; i < str.size(); i++)
After all, the index is not important in this situation.
Dealing with multiple spaces
Right now, both the OP's code and Allan's will push an empty string onto the output vector whenever they encounter more than one contiguous space. We can correct that by resetting the string to empty when a space is encountered, but when a space is encountered and the string is empty, don't take any action.
We also need to check if the string is non-empty when the loop is finished. If so, we need to push that onto the output vector. We may not get a trailing space to trigger pushing that last word.
vector<string> separate(string s) {
vector<string> output;
string current = "";
for (const char &ch : s) {
if (current != "" && ch == ' ') {
output.push_back(current);
current = "";
}
else if (ch == ' ') {
// Do nothing!
}
else {
current += ch;
}
}
if (current != "") {
output.push_back(current);
}
return output;
}
Putting it together so far
#include <string>
#include <vector>
#include <iostream>
using namespace std;
vector<string> separate(string s);
int main() {
auto v = separate("hello world foo");
for (auto i : v) {
cout << i << endl;
}
}
vector<string> separate(string s) {
vector<string> output;
string current = "";
for (const char &ch : s) {
if (current != "" && ch == ' ') {
output.push_back(current);
current = "";
}
else if (ch == ' ') {
// Do nothing!
}
else {
current += ch;
}
}
if (current != "") {
output.push_back(current);
}
return output;
}
Counting words
We can use a map to count the occurrences of words. We use a map<string, int> where each word is the key, and the val is the occurrences. As we iterate over the words, if the word already exists as a key in the map, we increment it by `. If not, we set it to 1.
int main() {
auto v = separate("hello world hello world foo");
map<string, int> m;
for (auto i : v) {
if (m[i]) {
m[i] += 1;
}
else {
m[i] = 1;
}
}
for (auto const& [key, val] : m) {
cout << "The word \"" << key << "\" occurs "
<< val << " times." << endl;
}
}

How do I make Palindrome function reverse more than one word

My palindrome function's supposed to find a word (or more than one word) in string, compare it with a bunch of other strings in the container, and if it finds one that's the same, reverse it, and stick them together. E.g. palindrome -> palindromeemordnilap, or if it's a more than one word: two words > two wordssdrow owt.
Mine's working for only one word, and also, for some reason, fails to correctly reverse the last one in the sentence. What should I, if even possible, change to accomplish the above?
#include <iostream>
#include <vector>
#include <string>
typedef std::vector<std::string> StringVektor;
std::string ReverseString(std::string s1)
{
std::string to_return(s1);
char temp(0);
for (int i(0); i < vrati.size() / 2; i++)
{
temp = to_return.at(i);
to_return.at(i) = to_return.at(to_return.length() - 1 - i);
to_return.at(to_return.length() - 1 - i) = temp;
}
return to_return;
}
std::string CreatePalindrome(String s, StringVektor v)
{
std::string compare;
for (int i(0); i < s.size(); i++)
{
if (s.at(i) != ' ')
compare += s.at(i);
if (s.at(i) == ' ' || i == s.length() - 1)
{
for (int j(0); j < v.size(); j++)
{
if (compare == v.at(j))
{
std::string put_in;
put_in = ReverseString(v.at(j));
s.insert(i, put_in);
}
}
compare.clear();
}
}
std::string to_return;
to_return = s;
return to_return;
}
int main ()
{
std::string sentence, phrase;
StringVektor v1;
std::cout << "Enter your sentence: ";
std::getline(std::cin, sentence);
std::cout << "Enter phrases: ";
for ( ;;)
{
std::getline(std::cin, phrase);
if(!fraza.empty())
v1.push_back(phrase);
if(std::cin.peek() == '\n')
break;
}
std::cout << "Your sentence after the transformation: " <<
CreatePalindrome(sentence, v1);
return 0;
}

Common word in vector with how many times word occurred C++

Hey everyone I am trying to figure out how to find the common word in a vector with how many times it occurred. My professor wants us to go through the vector with two for loops, but I am stuck because the loop will re-count already counted words and gives crazy outputs. I am a new programmer in my first programming class and finding all this very difficult. This is what I have so far.
#include <iostream>
#include <vector>
using namespace std;
int main() {
string s;
int max_count {1};
vector<string> input{};
while (cin >> s)
{
input.push_back(s);
}
for (int i = 0; i < input.size(); ++i)
{
for (int k = i + 1; k < input.size(); ++k)
{
if (input[i] == input[k])
{
s = input[k];
++max_count;
}
}
}
cout << s << " occurs " << max_count << " times " << endl;
return 0;
}
simple solution using no additional data structures:
int prevRel = -1;
std::string last = "";
for (int i = 0; i < input.size(); ++i)
{
int relcount = 0;
for (int k = 0; k < input.size(); ++k)
{
if (input[i] == input[k])
relcount++;
}
if(relcount > prevRel) {
prevRel = relcount;
last = input[i]
}
}
solution is now in last with an absolute number of prevRel occurences
This uses a map, so that one pass through the word list is required and a binary search is used to find the possibly matching word - meaning that it becomes more efficient the more words are input. If you input ten time more words, this will run LESS than ten times more slowly.
Running here
#include <iostream>
#include <vector>
#include <map>
using namespace std;
int main() {
vector<string> input
{ "the", "quick", "brown", "fox", "jumped",
"over", "the", "the", "lazy", "dog" };
map< string, int > histogram;
string most_common_word = input[0];
int max_count = 1;
// loop over words
for( auto& word : input)
{
// attempt to insert new word into histogram
auto p = histogram.insert( pair< string, int >( word, 1 ) );
if( ! p.second )
{
// word is not new, so increment count
p.first->second++;
// check for most common so far
if( p.first->second > max_count )
{
// remember most common so far
most_common_word = word;
max_count = p.first->second;
}
}
}
cout << "'" << most_common_word << "' occurs " << max_count << " times " << endl;
return 0;
}

c++ vector size and capacity outputting same value

when I was researching vectors, I noticed that size() is supposed to give the number of elements in the vector, right? So, when I found c++ does not have a string split() function built-in, I decided to make one. The problem is, vector.size() displays the same value as vector.capacity() as shown in the code:
#include <iostream>
#include <algorithm>
using namespace std;
void split(string input, char chr, vector<string> list) {
string add;
string conv;
int size = 0;
for (int i = 0; i <= input.size(); i++) {
if ((input[i] != char(chr)) && (input[i] != 0)) {
conv = input[i];
add += conv;
}
else {
cout << list.size() << endl;
if (size <= list.capacity()) {
list[size] = add;
add = "";
size++;
}
}
}
}
int main() {
vector<string> list(6);
split("test1,test2", ',', list);
for (int i = 0; i < 2; i++) {
cout << list[i] << endl;
}
}
The output is this:
6
6
<blank line>
<blank line>
whereas it SHOULD be this from my understanding:
1
2
test1
test2
Edit: if this is of any importance, I am compiling with -std=c++11
You initialize the vector with size 6, not capacity 6. It will be constructed with 6 empty elements inside and thus setting values 0 and 1 won't change that.
The reason why you see only blank lines is that you pass the vector by value instead of by reference to you split function.
#include <iostream>
#include <string>
#include <vector>
void split (const std::string& s, char sep, std::vector<std::string>& words)
{
if (s.empty()) return;
std::size_t beg = 0;
std::size_t end = s.find(sep, beg);
while (end != std::string::npos)
{
words.push_back(s.substr(beg, end - beg));
beg = end + 1;
end = s.find(sep, beg);
}
words.push_back(s.substr(beg));
}
int main() {
std::vector<std::string> words;
split("test1,test2", ',', words);
for (std::size_t i = 0; i != words.size(); ++i) {
std::cout << words[i] << std::endl;
}
return 0;
}