Inserting into a sorted array of structs in C++ - c++

I have to implement a vector using an array in C++ that is used to count the number of unique words from the input. It reads the input and then adds to the words to a struct which contains its count and the unique word and then this is added to the vector. I have successfully implemented insert. The problem is that I can't get the inserting/ incrementing unique word count to work (elements aren't added to the vector). Here is my code:
#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include "MyVector.h"
using namespace std;
struct wordCount{
string val;
int count;
};
int main(int argc, char** argv) {
enum { total, unique,individual } mode = total;
for (int c; (c = getopt(argc, argv, "tui")) != EOF;) {
switch(c) {
case 't': mode = total; break;
case 'u': mode = unique; break;
case 'i': mode = individual; break;
}
}
argc += optind;
argv += optind;
string word;
Vector<wordCount> words;
Vector<wordCount>::iterator it;
int count = 0;
while (cin >> word) {
count++;
if(mode == unique || mode == individual){
for(it=words.begin();it != words.end();it++){
if((it-1)->val <= word && it->val >= word){
// Found word, increment its count
if(it->val == word){
it->count++;
break;
}
// Otherwise insert the new unique word
else{
cout << "adding unique word" << endl;
wordCount* wc;
wc = new wordCount;
wc->val = word;
wc->count = 1;
words.insert(it,*wc);
break;
}
}
}
}
}
switch (mode) {
case total: cout << "Total: " << count << endl; break;
case unique: cout << "Unique: " << words.size() << endl; break;
case individual:
for(it=words.begin();it!=words.end();it++){
cout << it->val << ": " << it->count << endl;}
break;
}
}

It's hard to say anything without seeing your implementation of
Vector. If we assume it adheres to the standard container
conventions (and doesn't have an error in trying to do so): you
iterate starting with it.begin(), but immediately access
it-1. That's undefined behavior for a standard container. (I
don't know what it will do with your implementation ofVector`,
but it would take some tricky code to make it work.)
At a higher level, there seems a basic inconsistency: you're
keeping the vector sorted, but still using linear search. If
you're using linear search, there's no point in keeping the
vector sorted; just use:
Vector<wordCount>::iterator it = words.begin();
while ( it != words.end() && *it != word ) {
++ it;
}
if ( it == words.end() ) {
// not found, append to end...
} else {
// found, do whatever is appropriate...
}
(although I'd probably append to end, recover the iterator to
the newly inserted element, and treat it as if it were found).
Alternatively, if you're keeping the vector sorted, use a binary
search, not a linear search.
In either case, put the search in a separate function. (If this
wasn't homework, I'd say just use std::vector and either
std::find_if or std::lower_bound.)
Also, why the new in the innermost else? A more reasonable
approach would be to provide a constructor for wordCount
(which sets the count to 0), and do something like:
if ( ! found ) {
it = words.insert( wordCount( word ) );
}
++ it->count;
The definition of found will depend on whether you're using
binary search or not. In terms of the standard, this would be
either:
Vector<wordCount>::iterator it
= std::find_if( words.begin(), words.end(), MatchWord( word );
if ( it == words.end() ) {
it = words.insert( words.end(), wordCount( word ) );
}
++ it-count;
or
Vector<wordCount>::iterator it
= std::lower_bound( words.begin(), words.end(), word, CompareWord() );
if ( it == words.end() || it->val != word ) {
it = words.insert( wordCount( word ) );
++ it->count;
You should probably strive for something similar, with
a separate lookup function, returning either end, or the
position for the insertion when the value isn't found.
This keeps the various concerns clearly separated, and avoids
the excessive nesting in your code. (You should probably try to
avoid break in general, and in multiply nested ifs, it is
completely inacceptable—you'll notice that one of the
other people answering missed them, and misunderstood the
control flow because of it.)

Well, why don't you use a map? That's exactly what it's for, mapping from one thing to another. From a string (the word) to an int (the number of occurences) in your case. Or do you have to use a vector?

Try to use a std::map.
Counter::Map words;
Counter count(words);
std::for_each(
std::istream_iterator<std::string>(myInStream /*std::cin*/),
std::istream_iterator<std::string>(),
count);
std::copy(
words.begin(),
words.end(),
std::ostream_iterator<Counter::Map::value_type>(myOutStream /*std::cout*/, "\n"));
The Counter functor could look like this
struct Counter
{
typedef std::map<std::string, size_t> Map;
Counter(Map& m) : words(&m) {}
void operator()(const std::string& word)
{
Map::iterator it = words->lower_bound(word);
if (it == words->end() || it->first != word)
words->insert(it, std::make_pair(word, 1));
else
++it->second;
}
Map* words;
};
Using a std::vector
struct CounterVector
{
typedef std::vector<std::pair<std::string, size_t> > Vector;
CounterVector(Vector& m) : words(&m) {}
struct WordEqual
{
const std::string* s;
WordEqual(const std::string& w) : s(&w) {}
bool operator()(Vector::const_reference p) const {
return *s == p.first;}
};
void operator()(const std::string& word)
{
Vector::iterator it = std::find_if(
words->begin(), words->end(), WordEqual(word));
if (it == words->end())
words->push_back(std::make_pair(word,1));
else
++it->second;
}
Vector* words;
};

Related

How to "Fold a word" from a string. EX. "STACK" becomes "SKTCA". C++

I'm trying to figure out how to can fold a word from a string. For example "code" after the folding would become "ceod". Basically start from the first character and then get the last one, then the second character. I know the first step is to start from a loop, but I have no idea how to get the last character after that. Any help would be great. Heres my code.
#include <iostream>
using namespace std;
int main () {
string fold;
cout << "Enter a word: ";
cin >> fold;
string temp;
string backwards;
string wrap;
for (unsigned int i = 0; i < fold.length(); i++){
temp = temp + fold[i];
}
backwards= string(temp.rbegin(),temp.rend());
for(unsigned int i = 0; i < temp.length(); i++) {
wrap = fold.replace(backwards[i]);
}
cout << wrap;
}
Thanks
#Supreme, there are number of ways to do your task and I'm going to post one of them. But as #John had pointed you must try your own to get it done because real programming is all about practicing a lot. Use this solution just as a reference of one possibility and find many others.
int main()
{
string in;
cout <<"enter: "; cin >> in;
string fold;
for (int i=0, j=in.length()-1; i<in.length()/2; i++, j--)
{
fold += in[i];
fold += in[j];
}
if( in.length()%2 != 0) // if string lenght is odd, pick the middle
fold += in[in.length()/2];
cout << endl << fold ;
return 0;
}
good luck !
There are two approaches to this form of problem, a mathematically exact method would be to create a generator function which returns the number in the correct order.
An easier plan would be to modify the string to solve practically the problem.
Mathematical solution
We want a function which returns the index in the string to add. We have 2 sequences - increasing and decreasing and they are interleaved.
sequence 1 :
0, 1 , 2, 3.
sequence 2
len-1, len-2, len-3, len-4.
Given they are interleaved, we want even values to be from sequence 1 and odd values from sequence 2.
So our solution would be to for a given new index, choose which sequence to use, and then return the next value from that sequence.
int generator( int idx, int len )
{
ASSERT( idx < len );
if( idx %2 == 0 ) { // even - first sequence
return idx/2;
} else {
return (len- (1 + idx/2);
}
}
This can then be called from a function fold...
std::string fold(const char * src)
{
std::string result;
std::string source(src);
for (size_t i = 0; i < source.length(); i++) {
result += source.at(generator(i, source.length()));
}
return result;
}
Pratical solution
Although less efficient, this can be easier to think about. We are taking either the first or the last character of a string. This we will do using string manipulation to get the right result.
std::string fold2(const char * src)
{
std::string source = src;
enum whereToTake { fromStart, fromEnd };
std::string result;
enum whereToTake next = fromStart;
while (source.length() > 0) {
if (next == fromStart) {
result += source.at(0);
source = source.substr(1);
next = fromEnd;
}
else {
result += source.at(source.length() - 1); // last char
source = source.substr(0, source.length() - 1); // eat last char
next = fromStart;
}
}
return result;
}
You can take advantage of the concept of reverse iterators to write a generic algorithm based on the solution presented in Usman Riaz answer.
Compose your string picking chars from both the ends of the original string. When you reach the center, add the char in the middle if the number of chars is odd.
Here is a possible implementation:
#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>
#include <iterator>
template <class ForwardIt, class OutputIt>
OutputIt fold(ForwardIt source, ForwardIt end, OutputIt output)
{
auto reverse_source = std::reverse_iterator<ForwardIt>(end);
auto reverse_source_end = std::reverse_iterator<ForwardIt>(source);
auto source_end = std::next(source, std::distance(source, end) / 2);
while ( source != source_end )
{
*output++ = *source++;
*output++ = *reverse_source++;
}
if ( source != reverse_source.base() )
{
*output++ = *source;
}
return output;
}
int main() {
std::vector<std::pair<std::string, std::string>> tests {
{"", ""}, {"a", "a"}, {"stack", "sktca"}, {"steack", "sktcea"}
};
for ( auto const &test : tests )
{
std::string result;
fold(
std::begin(test.first), std::end(test.first),
std::back_inserter(result)
);
std::cout << (result == test.second ? " OK " : "FAILED: ")
<< '\"' << test.first << "\" --> \"" << result << "\"\n";
}
}

Write a c++ program that finds the number of vowels used in an string

Write a c++ program that finds the number of vowels used in an string.
For the above problem I written a program as follows:
int main()
{
char x[10];
int n,i,s=0;
cout<<"Enter any string\n";
cin>>x;
n=strlen(x);
for(i=0;i<n;++i)
{
if(x[i]=='a'||x[i]=='e'||x[i]=='i'||x[i]=='o'||x[i]=='u')
{
s=s+1;
}
}
cout<<s;
return 0;
}
Output of the program is as:
Enter any string elephant 3
Here in 'elephant' at three places vowels are used but the total number of vowels used is 2(e and a) not 3
I am asking to improve the program so that it counts the total number of vowels and print the total number.(e.g. in case of elephant it must give 2)
Make another array(), with 5 index, like
vowels[5] = array(0,0,0,0,0);
Then make if else if, with eache vowel, and add
if(x[i] == 'a') vowels[0] =1;
elseIf(x[i] == 'e') vowels[1] =1;
etc, and then check if vowels array is set to 1 or 0, and count only, these which are 5.
int count=0;
foreach vowels as item {
if(item == 1) count++
}
return count;
The easiest solution would be to just insert each vowel you see
into an std::set, and use its size function when you're
done.
And for heaven's sake, use a table lookup to determine whether
something is a vowel (and put the logic in a separate function,
so you can correct it when you need to handle the "sometimes y"
part).
Alternatively, without using the standard algorithms:
int charCount[UCHAR_MAX + 1];
// and for each character:
++ charCount[static_cast<unsigned char>( ch )];
(Of course, if you're using C++, you'll read the characters
into an std::string, and iterate over that, rather than having
an almost guaranteed buffer overflow.)
Then, just look at each of the vowels in the table, and count
those which have non-zero counts:
int results = 0;
std::string vowels( "aeiou" ); // Handling the sometimes "y" is left as an exercise for the reader.
for ( auto current = vowels.begin(); current != vowels.end(); ++ current ) {
if ( charCount[static_cast<unsigned char>( *current )] != 0 ) {
++ results;
}
}
Of course, neither of these, implemented naïvely, will handle
upper and lower case correctly (where 'E' and 'e' are the same
vowel); using tolower( static_cast<unsigned char>( ch ) ) will
solve that.
EDIT:
Since others are proposing solutions (which are only partially
correct):
bool
isVowel( unsigned char ch )
{
static std::set<int> const vowels{ 'a', 'e', 'i', 'o', 'u' };
return vowels.find( tolower( ch ) ) != vowels.end();
}
int
main()
{
std::string text;
std::cout << "Enter any word:";
std::cin >> text;
std::set<unsigned char> vowelsPresent;
for ( unsigned char ch: text ) {
if ( isVowel( ch ) ) {
vowelsPresent.insert( tolower( ch ) );
}
}
std::cout << vowelsPresent.size() << std::endl;
}
Separating the definition of a vowel into a separate function is
practically essential in well written code, and at the very
least, you need to mask differences in case. (This code also
punts on the question of "y", which would make isVowel several
orders of magnitude more difficult. It also ignores characters
outside of the basic character set, so "naïve" will report two
different vowels.)
Sets already eliminate duplicates, so instead of counting vowels as you encounter them, add them into a set. Then, at the end, count the number of [non-duplicate] vowels by querying the set for its size.
#include <set>
#include <string>
#include <iostream>
int main()
{
std::string x;
int n = 0;
std::set<char> vowels;
std::cout << "Enter any string\n";
std::cin >> x;
n = x.size();
for (int i = 0; i < n; ++i)
if (x[i] == 'a' || x[i] == 'e' || x[i] == 'i' || x[i] == 'o' || x[i] == 'u')
vowels.insert(x[i]);
std::cout << vowels.size() <<'\n';
}
Live demo
g++-4.8 -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && echo "elephant" | ./a.out
Enter any string
2
Note that I also exchanged your use of fixed-sized arrays with an std::string, so that you're not at risk of dangerous circumstances when someone happens to input more than 9 characters.
I find a really easy way to solve this problem is by using map <char, int>. This will allow you to make pairs, indexed by a char, ie. the vowels, and connect an integer counter to them.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
map <char, int> vowels;
int n,i,s=0;
string x;
cout<<"Enter any string\n";
cin>>x;
for(i=0;i< x.length();++i)
{
if(x[i]=='a'||x[i]=='e'||x[i]=='i'||x[i]=='o'||x[i]=='u')
{
vowels[x[i]]++;
}
}
for (map<char,int>::const_iterator print = vowels.begin(); print != vowels.end(); ++print){
cout << print -> first << " " << print -> second << endl;
}
return 0;
}
For the string elephant we would get the following output:
a 1
e 2
By saying vowels[x[i]]++; we are adding the found vowel into our map, if it already has not been added, and incrementing its paired int by one. So when we find the first e it will add e to our map and increment its counter by one. Then it will continue until it finds the next e and will see that it already has that indexed, so it will simply increment the counter to 2. This way we will avoid the problem with duplicates. Of course, if you wanted to get a single digit we could just print out the size of our map:
cout << vowels.size() << endl;
Okay. My turn. To handle both upper and lower cases we convert to just lower:
std::string x("Elephant");
std::transform(x.begin(), x.end(), x.begin(), std::function<int(char)>(std::tolower));
Now remove duplicates:
std::sort(x.begin(), x.end());
std::unique(x.begin(), x.end());
Now to count the vowels. I was hoping for something specific in locale but alas... Never mind we can create our own. Bit more complex, but not overly:
struct vowel : public std::ctype<char>
{
static const mask* make_table()
{
static std::vector<mask> v(classic_table(), classic_table() + table_size);
v['a'] |= upper;
v['e'] |= upper;
// etc.
return &v[0];
}
vowel(std::size_t refs = 0) : ctype(make_table(), false, refs){}
};
While I am sure you can create your own but can't quite figure out how going by the documentation on cppreference so I say lower case vowels are uppercase. With the earlier call to std::tolower this should be safe.
With this we can use it easily like:
int i = std::count_if(x.begin(), x.end(), [](const char c)
{
return std::isupper(c, std::locale(std::locale(""), new vowel));
});
std::cout << "Number of vowels:" << i << std::endl;
However I am not particularly happy with the two std::locale next each other.
Easiest solution I can think of would be an array of bools representing each vowel and whether or not they've been counted.
bool vowelCounted[5] = { false };
Now, as you count the vowels:
if (x[i]=='a' && !vowelCounted[0]) {
vowelCounted[0] = true;
s += 1;
} else if (x[i]=='e' && !vowelCounted[1]) {
vowelCounted[1] = true;
s += 1;
}
And just repeat this structure for all 5 vowels.
The readability can be improved by using an enum rather than 0, 1, 2, 3, 4 for your indices... but you're using variables named x[] and s, so it's probably fine...
If you use one of the standard containers (vector, list) add your vowels in there, do the same check as you're doing now, if it exists then remove it. When you're finished get the number of remaining elements, your answer will be the original count for the vowels minus the the remaining elements.
try this
for( string text; getline( cin, text ) && text != "q"; )
{
set< char > vowels;
copy_if( begin(text), end(text), inserter( vowels, begin(vowels) ),
[]( char c ) { return std::char_traits< char >::find( "aeiou", 5, c ) != nullptr; } );
cout << "the string [" << text << "] contains " << vowels.size() << " vowels" << endl;
}
You need the includes string, iostream, set, algorithm and iterator.
What do You want to do with the upper ones "AEIOU" ?
You can create this:
std::vector< char> vowels;
And put into it all vowels that you meet while iterating through the string:
if(x[i]=='a'||x[i]=='e'||x[i]=='i'||x[i]=='o'||x[i]=='u')
vowels.push_back( x[i]);
Then you can sort this and eliminate duplicates:
std::sort( vowels.begin(), vowels.end());
std::vector< char> vowels_unique( vowels.size());
std::vector< char>::iterator it;
it = std::unique_copy( vowels.begin(), vowels.end(), vowels_unique.begin());
vowels_unique.resize( std::distance( vowels_unique.begin(), it));
Even better, use a set property - it holds unique data, like this:
std::set< char> unique_vowels;
if(x[i]=='a'||x[i]=='e'||x[i]=='i'||x[i]=='o'||x[i]=='u')
unique_vowels.insert( x[i]);
//...
int unique = unique_vowels.size();
C++ Code Snippet :
#include <bits/stdc++.h>
using namespace std;
int main()
{
char s[100];
int cnt;
cnt=0;
cin>>s;
for(int i=0;s[i];i++)
{
char c =s[i];
if(s[i]=='A' || s[i] =='E' || s[i]=='I' ||s[i]=='O'|| s[i]=='U') cnt++;
else if(s[i]=='a' || s[i] =='e' || s[i]=='i'||s[i]=='o' || s[i]=='u') cnt++;
}
cout<<cnt<<endl;
return 0;
}
Version utilizing std::find() and std::transform():
#include <string>
#include <iostream>
#include <algorithm>
using std::string;
using std::cout;
using std::cin;
using std::getline;
using std::transform;
int main()
{
cout << " Type sentence: ";
string sentence;
getline(cin, sentence);
transform(sentence.begin(), sentence.end(), sentence.begin(), toupper);
string vowels = "AEIOU";
size_t vowCount = 0;
for (int i = 0; i < vowels.length(); ++i)
{
if (sentence.find(vowels[i], 0) != string::npos)
{
++vowCount;
}
}
cout << "There is " << vowCount << " vowels in the sentence.\n";
return 0;
}
PROS
std::find() searches just for first occurrence of given vowel so there is no iteration over rest of the given string
using optimized algorithms from std
CONS
std::transform() transforms each lower-case letter regardless of its "vowelness"
#include<iostream> //std::cout
#include<string> //std::string
#include<cctype> //tolower()
#include<algorithm> //std::for_each
using namespace std;
int main()
{
string s;
getline(cin, s);
int count = 0;
for_each(s.begin(), s.end(), [&count](char & c) //use of lambda func
{
c = tolower(c); //you can count upper and lower vowels
switch (c)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
count++;
break;
}
});
cout << count << endl;
return 0;
}
#include<iostream>
using namespace std;
int main()
{
char vowels[5] = {'a','e','i','o','u'};
char x[8] = {'e','l','e','p','h','a','n','t'};
int counts[5] = {0,0,0,0,0};
int i,j;
for(i=0;i<8;i=i+1)
{
for(j=0;j<5;j=j+1)
{
if(x[i]==vowels[j])
{
counts[j] = counts[j] + 1;
}
}
}
for(i=0;i<5;i=i+1)
{
cout<<counts[i]<<endl;
}
return 0;
}
Since I was using the example of 'elephant' so I just initialized that.
If still any modification can be made then please edit it and make it more user friendly.

Get three most occuring word with their count value from vector and unordered_map

My below code gives me most occurring word from string. I wan to get get three most occuring words from vector with their count value. Any help?
I have used vector and unordered_map. In last portion of code I got most occuring word from vector.
int main(int argc,char *argv[])
{
typedef std::unordered_map<std::string,int> occurrences;
occurrences s1;
std::string input = argv[1];
std::istringstream iss(std::move(input));
std::vector<std::string> most;
int max_count = 0,second=0,third=0;
//Here I get max_count, 2nd highest and 3rd highest count value
while (iss >> input)
{
int tmp = ++s1[input];
if (tmp == max_count)
{
most.push_back(input);
}
else if (tmp > max_count)
{
max_count = tmp;
most.clear();
most.push_back(input);
third = second;
second = max_count;
}
else if (tmp > second)
{
third = second;
second = tmp;
}
else if (tmp > third)
{
third = tmp;
}
}
//I have not used max_count, second, third below. I dont know how to access them for my purpose
//Print each word with it's occurenece. This works fine
for (occurrences::const_iterator it = s1.cbegin();it != s1.cend(); ++it)
std::cout << it->first << " : " << it->second << std::endl;;
//Prints word which occurs max time. **Here I want to print 1st highest,2nd highest,3rd highest occuring word with there occurrence. How to do?**
std::cout << std::endl << "Maximum Occurrences" << std::endl;
for (std::vector<std::string>::const_iterator it = most.cbegin(); it != most.cend(); ++it)
std::cout << *it << std::endl;
return 0;
}
Any idea to get 3 most occuring word?
I'd prefer to use a std::map<std::string, int> instead
Use this as a source map, insert values from a std::vector<std::string>
Now create multimap, a flip version of source map with std::greater<int> as Comparator
This final map has top three value as most frequent used words
Example :
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
int main()
{
std::vector<std::string> most { "lion","tiger","kangaroo",
"donkey","lion","tiger",
"lion","donkey","tiger"
};
std::map<std::string, int> src;
for(auto x:most)
++src[x];
std::multimap<int,std::string,std::greater<int> > dst;
std::transform(src.begin(), src.end(), std::inserter(dst, dst.begin()),
[] (const std::pair<std::string,int> &p) {
return std::pair<int,std::string>(p.second, p.first);
}
);
std::multimap<int,std::string>::iterator it = dst.begin();
for(int count = 0;count<3 && it !=dst.end();++it,++count)
std::cout<<it->second<<":"<<it->first<<std::endl;
}
DEMO HERE
It is easier and cleaner to use a heap to store the three most occuring words. It also is easily extensible to a larger number of most occuring words.
If I wanted to know the n most occurring words, I'd have an n element array, iterate over the list of the words, and store the ones that make it into my top n into the array (dropping the lowest one).

What data structure is better to use to find if sentence consist of unique characters?

I'm trying to solve a task and not sure if I'm using suitable data structure for it. My task is to find if sentence consist of unique characters and as a result return boolean value.
Here is my function:
bool use_map(string sentence) {
map<int, string> my_map;
for (string::size_type i = 0; i <= sentence.length(); i++) {
unsigned int index = (int)sentence[i];
if (my_map.find(index) != my_map.end())
return false;
my_map[index] = sentence[i];
}
return true;
}
I found only map structure which is suitable for me. Maybe I miss something?
Maybe it's better to use something like dynamic arrays at PHP?
I'm trying to use hash table solution.
The other answers suggested std::set and that's a solution. BUT, they copy all chars inside the std::set and then get the size of the set. You don't really need this and you can avoid it, using the return value of std::set::insert. Something like:
std::set< char > my_set;
for (std::string::size_type ii = 0; ii < sentence.size(); ++ii)
{
if( ! my_set.insert( sentence[ ii ] ).second )
{
return false;
}
}
This way you'll:
stop on the first duplicated char and you will not copy the whole string (unnecessarily)
you will avoid the unnecessary cast to int in your code
will save memory - if you don't actually need you std::map< int, std::string >::second
Also, make sure you need to "count" all chars or you want to skip some of them (like white spaces, commas, question marks, etc)
A very simple (but rather memory expensive) way would be:
bool use_map(const std::string& sentence)
{
std::set<char> chars(sentence.begin(), sentence.end());
return chars.size() == sentence.size();
}
If there's no duplicate chars, the sizes of both string and set will be equal.
#Jonathan Leffler raises a good point in the comments: sentences usualy contain several whitespaces, so this will return false. You'll want to filter spaces out. Still, std::set should be your container of choice.
Edit:
Here's an idea for O(n) solution with no additional memory. Just use a look-up table where you mark if the char was seen before:
bool no_duplicates(const std::string& sentence)
{
static bool table[256];
std::fill(table, table+256, 0);
for (char c : sentence) {
// don't test spaces
if (c == ' ') continue;
// add more tests if needed
const unsigned char& uc = static_cast<unsigned char>(c);
if (table[uc]) return false;
table[uc] = true;
}
return true;
}
I guess an easy way is to store all the characters in an associative container that does not allow duplicates, such as std::set, and check if it contains a single value:
#include <set>
#include <string>
bool has_unique_character(std::string const& str)
{
std::set<char> s(begin(str), end(str));
return (s.size() == str.size());
}
What about this? There is a case issue of course...
bool use_map(const std::string& sentence)
{
std::vector<bool> chars(26, false);
for(std::string::const_iterator i = sentence.begin(); i != sentence.end(); ++i) {
if(*i == ' ' || *i - 'a' > 25 || *i - 'a' < 0) {
continue;
} else if(chars[*i - 'a']) {
return false;
} else {
chars[*i - 'a'] = true;
}
}
return true;
}
Sort the characters and then look for an adjacent pair of alphabetic characters with both characters equal. Something like this:
std::string my_sentence = /* whatever */
std::sort(my_sentence.begin(), my_sentence.end());
std::string::const_iterator it =
std::adjacent_find(my_sentence.begin(), my_sentence.end());
while (it != my_sentence.end() && isalpha((unsigned char)*it)
it = std::adjacent_find(++it, my_sentence.end());
if (it == my_sentence.end())
std::cout << "No duplicates.\n";
else
std::cout << "Duplicated '" << *it << "'.\n";
If you are allowed to use additional memory, use a hash table: Iterate through the array, check if current element has already been hashed. If yes, you found a repetition. If no, add it to hash. This will be linear, but will require additional memory.
If the range of original sequence elements is quite small, instead of hashing you can simply have an array of the range size and do like in a bucket sort. For example
bool hasDuplicate( string s )
{
int n = s.size();
vector<char> v( 256, 0 );
for( int i = 0; i < n; ++i )
if( v[ s[ i ] ] ) // v[ hash( s[i] ) ] here in case of hash usage
return true;
else
v[ s[ i ] ] = 1; // and here too
return false;
}
Finally, if you are not allowed to use additional memory, you can just sort it and check if two adjacent elements are equal in one pass. This will take O(nlogn) time. No need for sets or maps :)
Here is the fastest possible solution:
bool charUsed[256];
bool isUnique(string sentence) {
int i;
for(i = 0; i < 256; ++i) {
charUsed[i] = false;
}
int n = s.size();
for(i = 0; i < n; ++i) {
if (charUsed[(unsigned char)sentence[i]]) {
return false;
}
charUsed[(unsigned char)sentence[i]] = true;
}
return true;
}

C++ Counting words in a file between two words

I am currently trying to count the number of words in a file. After this, I plan to make it count the words between two words in the file. For example. My file may contain. "Hello my name is James". I want to count the words, so 5. And then I would like to count the number of words between "Hello" and "James", so the answer would be 3. I am having trouble with accomplishing both tasks.
Mainly due to not being exactly sure how to structure my code.
Any help on here would be greatly appreciated. The code I am currently using is using spaces to count the words.
Here is my code:
readwords.cpp
string ReadWords::getNextWord()
{
bool pWord = false;
char c;
while((c = wordfile.get()) !=EOF)
{
if (!(isspace(c)))
{
nextword.append(1, c);
}
return nextword;
}
}
bool ReadWords::isNextWord()
{
if(!wordfile.eof())
{
return true;
}
else
{
return false;
}
}
main.cpp
main()
{
int count = 0;
ReadWords rw("hamlet.txt");
while(rw.isNextWord()){
rw.getNextWord();
count++;
}
cout << count;
rw.close();
}
What it does at the moment is counts the number of characters. I'm sure its just a simple fix and something silly that I'm missing. But I've been trying for long enough to go searching for some help.
Any help is greatly appreciated. :)
Rather than parse the file character-by-character, you can simply use istream::operator<<() to read whitespace-separated words. << returns the stream, which evaluates to true as a bool when the stream can still be read from.
vector<string> words;
string word;
while (wordfile >> word)
words.push_back(word);
There is a common formulation of this using the <iterator> and <algorithm> utilities, which is more verbose, but can be composed with other iterator algorithms:
istream_iterator<string> input(wordfile), end;
copy(input, end, back_inserter(words));
Then you have the number of words and can do with them whatever you like:
words.size()
If you want to find "Hello" and "James", use find() from the <algorithm> header to get iterators to their positions:
// Find "Hello" anywhere in 'words'.
const auto hello = find(words.begin(), words.end(), "Hello");
// Find "James" anywhere after 'hello' in 'words'.
const auto james = find(hello, words.end(), "James");
If they’re not in the vector, find() will return words.end(); ignoring error checking for the purpose of illustration, you can count the number of words between them by taking their difference, adjusting for the inclusion of "Hello" in the range:
const auto count = james - (hello + 1);
You can use operator-() here because std::vector::iterator is a “random-access iterator”. More generally, you could use std::distance() from <iterator>:
const auto count = distance(hello, james) - 1;
Which has the advantage of being more descriptive of what you’re actually doing. Also, for future reference, this kind of code:
bool f() {
if (x) {
return true;
} else {
return false;
}
}
Can be simplified to just:
bool f() {
return x;
}
Since x is already being converted to bool for the if.
To count:
std::ifstream infile("hamlet.txt");
std::size_t count = 0;
for (std::string word; infile >> word; ++count) { }
To count only between start and stop:
std::ifstream infile("hamlet.txt");
std::size_t count = 0;
bool active = false;
for (std::string word; infile >> word; )
{
if (!active && word == "Hello") { active = true; }
if (!active) continue;
if (word == "James") break;
++count;
}
I think "return nextword;" should instead be "else return nextword;" or else you are returning from the function getNextWord every time, no matter what the char is.
string ReadWords::getNextWord()
{
bool pWord = false;
char c;
while((c = wordfile.get()) !=EOF)
{
if (!(isspace(c)))
{
nextword.append(1, c);
}
else return nextword;//only returns on a space
}
}
To count all words:
std::ifstream f("hamlet.txt");
std::cout << std::distance (std::istream_iterator<std::string>(f),
std::istream_iterator<std::string>()) << '\n';
To count between two words:
std::ifstream f("hamlet.txt");
std::istream_iterator<std::string> it(f), end;
int count = 0;
while (std::find(it, end, "Hello") != end)
while (++it != end && *it != "James")
++count;
std::cout << count;
Try this:
below the line
nextword.append(1, c);
add
continue;