1
\$\begingroup\$
  • Write a program to read strings from standard input looking for duplicated words.
  • The program should find places in the input where one word is followed immediately by itself.
  • Keep track of the largest number of times a single repetition occurs and which word is repeated.
  • Print the maximum number of duplicates, or else print a message saying that no word was repeated.

For example, if the input is

  • how now now now brown cow cow

the output should indicate that the word now occurred three times.


#include <iostream>
#include <string>

int main()
{
    using std::cin; using std::cout; using std::endl;
    using std::string;

    // running median
    string most_duplicated_str;
    int most_duplicated_count = 0;

    // loop variables
    string prev_str;
    string new_str;
    int new_duplicate_count = 1;

    while(cin >> new_str)
    {
        if (new_str != prev_str)
        {
            // check and update median
            if (new_duplicate_count > most_duplicated_count)
            {
                most_duplicated_str = prev_str;
                most_duplicated_count = new_duplicate_count;
            }

            // update prev_str
            new_duplicate_count = 1;
            prev_str = new_str;
            continue;
        }

        ++new_duplicate_count;
        prev_str = new_str;
    }

    // check and update median for last word
    if (new_duplicate_count > most_duplicated_count)
    {
        most_duplicated_str = prev_str;
        most_duplicated_count = new_duplicate_count;
    }

    // print result
    if(most_duplicated_count == 0)
        cout << "# No Duplicated Words #\n";
    else
        cout << "Most duplicated word: " << most_duplicated_str << ", " << most_duplicated_count << " times.\n";
}
\$\endgroup\$
6
  • 1
    \$\begingroup\$ Sure you need to keep track of all words and their counts until there are only "M" words left (where M < the distinct words) at that point you can throw away the counts for the words that couldn't possibly be in the total. Of course it's just easier to count them all, and then pick the max; \$\endgroup\$ – Mr R Mar 22 at 22:13
  • 4
    \$\begingroup\$ It's not clear to me from those misty 'rules' if in blue blue red red red blue green blue the blue should be output as the word with most occurences (4) or the red as the word with most occurences in a row (3). \$\endgroup\$ – CiaPan Mar 23 at 18:20
  • 1
    \$\begingroup\$ There is median, and there is mode. \$\endgroup\$ – greybeard Mar 24 at 2:50
  • \$\begingroup\$ @MrR I ALWAYS forget about short circuit stuff like this. Thanks for the tip - I'll change it to do that tonight! \$\endgroup\$ – Natalo77 Mar 24 at 10:28
  • \$\begingroup\$ @CiaPan Yeah it's kinda wack how the book asks me questions sometimes, but I just took it as the in a row thing \$\endgroup\$ – Natalo77 Mar 24 at 10:30
3
\$\begingroup\$

Nothing awful here.

If this was production code then putting things in named functions would be nice to help with self documenting code.


Don't particularly like this.

    using std::cin; using std::cout; using std::endl;
    using std::string;

But I am not going to complain about it very much.


Using snake case is unusual but not unheard of in C++.

    string most_duplicated_str;
    int most_duplicated_count = 0;

Like the long descriptive names and the grouping of you variables into logical combinations.


I would note that:

      cin >> new_str

Reads a white space separated word. For college and learning purposes this will be fine. But in real life you would have to consider punctuation and other non alphabetical content and what to do with it.


Not a very useful comment.
I would either make it more descriptive (more words) or remove it.

    // loop variables

and

            // update prev_str

These three lines can be simplified:

            new_duplicate_count = 1;
            prev_str = new_str;
            continue;

to:

            new_duplicate_count = 0;

It will have the same effect and the loop will feel more logical as the same action happens every loop. But that's just my opinion on readability. If you did not change it I would not oppose it being merged into mainline.


If any words are read: Can the value ever be zero?

    // print result
    if(most_duplicated_count == 0)
        cout << "# No Duplicated Words #\n";
    else

If you only have a duplicate count of 1 were there any duplicates?
What happens if there are ties in the number of duplicate counts?

These are good questions to ask your customer! :-)

\$\endgroup\$
8
  • \$\begingroup\$ Thank you so much for the awesome & detailed answer! I did want to use functions, but the book I'm going through hasn't introduced them yet, so I didn't want to skip ahead too much. I see a lot of debate around namespace techniques. Do you prefer fully qualifiying everything? Regarding cin, is there a good resource for standard input reading techniques for stuff like this? I totally missed that simplification! Is there any way I can get around doing that final check of repeated code after the while? \$\endgroup\$ – Natalo77 Mar 24 at 10:38
  • \$\begingroup\$ Do you prefer fully qualifiying everything? Depends on context. If I am using code from another namespace I will fully qualify it. std::cin << "Info\n"; If the namespace is too long I will add a namespace alias and use that: namespace BSL = boost::Butcher::Streaming::Logs; BSL::log << "Info\n"; If this is code for my code and I am in the source file for a specific header file that uses a namespace I will use using namespace ThorsAnvil::DB::Access; See \$\endgroup\$ – Martin York Mar 24 at 18:26
  • \$\begingroup\$ Regarding cin, is there a good resource for standard input reading techniques for stuff like this? Sorry this is just tuff you learn as you go. I don't have any good references except SO and this site. Don't miss the use of operator>> and std::getline() use one or the other. Lots of SO questions on that subject. \$\endgroup\$ – Martin York Mar 24 at 18:27
  • \$\begingroup\$ Snake case isn't so unusual in C++: there's an entire Standard Library leading the way... \$\endgroup\$ – Toby Speight Mar 25 at 10:59
  • \$\begingroup\$ @TobySpeight Which one? Don't particularly have any objects to snake case (just the use of prefix _) but it is not my favorite (the _ is in a funny place on the keyboard for a lot of repetitive use). As long as people are consistent I am happy (consistent means we can automate things). \$\endgroup\$ – Martin York Mar 25 at 17:28
1
\$\begingroup\$

Create a testable function

Instead of plonking everything in main(), I would prefer to see a function which can be tested with many different inputs from one program (perhaps accepting a std::istream&, or maybe a pair of iterators to words).

Yes, you could write a shell script to invoke the program with different input streams, but that gets awkward when we want to test different parts of a larger program. Let's develop the habit of coding for testability right from the start.

One advantage of writing the tests as we go is that it helps us understand how the function will be called, leading us to a better interface. And we can investigate the edge cases (what if there are two words with the same repeat count? How should we deal with two different runs of the same word?).

Know your standard <algorithm>s

If we read input using a std::istream_iterator<std::string>, then we could use std::adjacent_difference() to compare consecutive words and maintain count, without having to hand-roll our own loops. Or we might (ab)use std::adjacent_find() or std::unique(), both of which have Ranges versions.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.