[ / / / / / / / / / / / / / ] [ dir / arepa / hentai / hkpol / leftpol / s8s / shota / tulpa / vor ][Options][ watchlist ]

/prog/ - Programming

Programming board
You can now write text to your AI-generated image at https://aiproto.com It is currently free to use for Proto members.
Name
Email
Subject
Comment *
Password (Randomized for file and post deletion; you may also set your own.)
* = required field[▶ Show post options & limits]
Confused? See the FAQ.
Expand all images

File (hide): 1435392700544.jpg (26.16 KB, 381x500, 381:500, C primer.jpg) (h) (u)

[–]

cd62a1 (8) No.2719>>5132 [Watch Thread][Show All Posts]

So, I'm reading C++ Primer 5th edition, I get to chapter 5, and, I'm not sure how to go about solving one of the exercises.

When I get stuck I typically look at how the problem was solved here https://github.com/Mooophy/Cpp-Primer.

But there's a fatal error in how they solve it.

They use pair, and when I look that up in the back of the book, that type doesn't appear for about 230 more pages, and isn't even mentioned beforehand, as they sometimes do with "there's this we'll discuss later"

The exercise is as follows.

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.

I'm thinking that I'd start with a vector of strings, and a string variable, use a while loop to get input into the string variable, using .push_back to put the strings into the vector.

Then create a for loop to go through the string vector, comparing the current string to the next one, and upping a counter.

My issue being, what do I do to make it so, if I find say 3 of a word, and then 4 of a different word, make it use the 4, not the 3, and not have a counter just go from 3 to 7?

cd62a1 (8) No.2720>>2724

Me again, so, so far I have this

// string repetition

#include <iostream>

#include <vector>

#include <string>

using namespace std;

int main()

{

vector<string> words;

vector<int> counter(2, 0);

cout << counter[0] << " " << counter[1] << endl;

string word = " ";

int fuckyall = 0;

string quit = "quit";

while(cin >> word && word != quit)

{

words.push_back(word);

}

string otherWord;

int i = 0;

for(auto beg = words.begin(); beg < words.end(); beg++)

{

word = words[i];

i++;

if(word == words[i])

{

while(word == words[i])

{

counter[1] + 1;

i++;

}

}

else

{

if(counter[1] > counter[0])

{

counter[0] = counter[1];

fuckyall = i;

}

}

}

cout << "The word " << words[fuckyall] << " was repeated " << counter[0] << " times." << endl;

return 0;

}

but when I run it, I do the input, and then it crashes, and I'm not sure what exactly is causing it as someone fairly new to programming.


cd62a1 (8) No.2721

also after posting I recognized an error in not resetting counter[1] after putting its value into counter[0]


cd62a1 (8) No.2724

>>2720

Add debug lines… and consider using .at() insted of [] on vectors


cd62a1 (8) No.2726>>2727

I wrote a solution for you, OP. I didn't end up using a vector, since you really only need to know two things each time you read a word:

- the previous word

- the number of times it has repeated

Also, instead of waiting for a magical "quit" word, I just used the eof() method to check for when the standard input file ended. At a terminal, you can indicate EOF in standard input by pressing CTRL-D on a new line. If you pipe a file to the command, it will automatically get an EOF at the end of the file.

I tried to put useful comments in place. Here it is:

#include <iostream>
#include <string>

using namespace std;

int main()
{
// The word which occurred most
string mostWord;
// The number of times it occurred (set to 1, since it's the minimum)
int mostCount = 1;

// The last word we read
string lastWord;
// The new word we'll be reading
string currWord;
// The count for the number of times that the current word has repeated
int currCount = 1;

cin >> lastWord;
while (cin >> currWord) {
bool eof = cin.eof();

if (lastWord == currWord && !eof) {
// If the new word is the same as the last one, increase the count
++currCount;
} else {
// Check if we set a new record for most consecutive occurrences. If
// we did, then update mostCount and mostWord accordingly.
if (currCount > mostCount) {
mostCount = currCount;
mostWord = lastWord;
}
// Reset lastWord and currCount
lastWord = currWord;
currCount = 1;
}
// If we've reached the end of the file (e.g. someone pressed CTRL-D at
// the terminal) then exit.
if (eof) break;
}

// Print output
if (mostCount > 1) {
cout << "The string " << mostWord << " occurred " << mostCount <<
" consecutive times.\n";
} else {
cout << "No duplicated words.\n";
}

return 0;
}


cd62a1 (8) No.2727>>2728

>>2726

Shoot, there are some problems with that code.

Please forgive me; I don't know C++ (only C, I had to look up the libraries to write this). Don't worry, this code doesn't leak any memory, at least (I actually ran it through valgrind because I *really* don't know C++, but it turned out alright).

Here is the revised code. You'll notice that we don't need to check for EOF, because apparently the >> operator does that for us on its own. I also added another test after the while loop; the reason for this will be left as an exercise for the reader.

#include <iostream>
#include <string>

using namespace std;

int main()
{
// The word which occurred most
string mostWord;
// The number of times it occurred (set to 1, since it's the minimum)
int mostCount = 1;

// The last word we read
string lastWord;
// The new word we'll be reading
string currWord;
// The count for the number of times that the current word has repeated
int currCount = 1;

cin >> lastWord;
while (cin >> currWord) {
if (lastWord == currWord) {
// If the new word is the same as the last one, increase the count
++currCount;
} else {
// Check if we set a new record for most consecutive occurrences. If
// we did, then update mostCount and mostWord accordingly.
if (currCount > mostCount) {
mostCount = currCount;
mostWord = lastWord;
}
// Reset lastWord and currCount
lastWord = currWord;
currCount = 1;
}
}

// We need to check once more whether the last word was the most repeated
if (currCount > mostCount) {
mostCount = currCount;
mostWord = lastWord;
}

// Print output
if (mostCount > 1) {
cout << "The string " << mostWord << " occurred " << mostCount <<
" consecutive times.\n";
} else {
cout << "No duplicated words.\n";
}

return 0;
}


cd62a1 (8) No.2728

>>2727

Thanks, since I just got off a 12 hour day I'll save it and read over it later, I was probably over thinking the problem when I wrote the code… it was 1am and I hadn't slept in a couple days… fucking 80 degree nights


cd62a1 (8) No.4402


#include <bits/stdc++.h>
#define pb push_back

void count_words(std::vector<std::string> &words){
std::string word;
int n = 0;
int nnew;
for(auto &i: words){
std::cout << i << ' ';
if(i != word){
nnew = std::count(words.begin(), words.end(), i);
if(nnew > n){
word = i;
n = nnew;
}
}
}
std::cout << '\n';
if(n > 1)
std::cout << "The word " << word << " occured " << n << " times\n";
else
std::cout << "No word is repeated!\n";
}

int main(){
std::string input;
std::vector<std::string> words;

while(std::cin >> input && input != "quit"){
words.pb(input);
}
count_words(words);
}

That's a solution with vectors.

It also works, if the word isn't immediately repeated after itself, but occurs later.


f8362c (1) No.4729

import std.stdio, std.algorithm, std.string, std.range;

void main(string[] args)
{
auto input = stdin.readln.strip.splitter.array;

if (input.filter!(w => input.count(w) == 1).array == input)
writeln("No words were duplicated");
else
writefln("\"%s\" was repeated %s times.", input.maxCount[0], input.maxCount[1]);
}

//hurr durr Keep track of the largest number of times a single repetition occurs and which word is repeated for no reason


5a6727 (1) No.5132>>5147 >>5153 >>5156

>>2719 (OP)

C++11. God STL is beautiful. Depending on the problem requirements, there might be a way to take advantage of std::unique to find consecutive duplicates, but it rearranges your line and if words can be repeated across multiple non-contiguous 'blocks' that wouldn't work. This works though, and its short.



#include <bits/stdc++.h>

using namespace std;

int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);

// Reads from standard input, expects whitespace-separated strings, stops at
// EOF
vector<string> v;
copy(istream_iterator<string>(cin), istream_iterator<string>(),
back_inserter(v));

// track repetition counter, and update best
int c = 0;
pair<int, string> ans = make_pair(0, "");
adjacent_difference(v.begin(), v.end(), v.begin(), [&](string a, string b) {
if (a == b) {
c++;
ans = (c > ans.first) ? make_pair(c, a) : ans;
} else
c = 0;
return a;
});

// answer
if (ans.first > 0)
cout << "Found word '" << ans.second << "' with " << ans.first + 1
<< " consecutive occurrences.\n";
else
cout << "No duplicates found.\n";

return 0;
}

// Sample input:
// how now now now now brown cow cow cow cow cow

// Sample output:
// Found word 'cow' with 5 consecutive occurrences.



d23384 (8) No.5147>>5148

>>5132

> // Reads from standard input, expects whitespace-separated strings, stops at

> // EOF

> vector<string> v;

> copy(istream_iterator<string>(cin), istream_iterator<string>(),

> back_inserter(v));

You're doing it wrong anon. std::getline is made for this type of operation, and will intrinsically be more efficient as well.

https://en.cppreference.com/w/cpp/string/basic_string/getline

And, if you're going to process many lines from an input file (seems to me a more plausible scenario) then wrap the the getline in a while().

https://cpppatterns.com/patterns/read-line-by-line.html


d23384 (8) No.5148

>>5147

Actually, check that. The for() in the first link is the more idiomatic modern C++, because the temp string stays contained in the scope of the loop. So, scratch that second suggestion I guess.


d23384 (8) No.5153>>5155

>>5132

Interesting use of adjacent_difference anon. If I were intending to use this in production (as opposed to a class project) I would take the time to refactor out the vector load. And tbqh your approach as is, is a bit non-standard. Use getline and stringstreams.


#include <iostream>
#include <numeric>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

using std::adjacent_difference;
using std::cout;
using std::getline;
using std::make_pair;
using std::pair;
using std::string;
using std::stringstream;
using std::vector;

vector<string> load_inputs(const string& input) {
stringstream input_ss;
input_ss << input; // load the stringstream

// Load a vector with whitespace-separated strings
vector<string> ret;
string tmp;
while (input_ss >> tmp) ret.emplace_back(tmp);

return ret; // rvo w/ vector
}

int main() {
string input;
getline(std::cin, input);
vector<string> inputs = load_inputs(input);

// track repetition counter, ranked by frequency
int cntr{0};
pair<int, string> ans = make_pair(0, "");
adjacent_difference(inputs.begin(), inputs.end(), inputs.begin(),
[&](string a, string b) {
if (a == b) {
++cntr;
ans = (cntr > ans.first) ? make_pair(cntr, a) : ans;
} else
cntr = 0;
return a;
});

if (ans.first > 0)
cout << "Found word '" << ans.second << "' with " << ans.first + 1
<< " consecutive occurrences.\n";
else
cout << "No duplicates found.\n";
}

/*
Sample input:
how now now now now brown cow cow cow cow cow

Sample output:
Found word 'cow' with 5 consecutive occurrences.
*/


d23384 (8) No.5155

>>5153

BTW, looking at it I would rename the utility function to parse_input(), so that the call site would now look like this:

  string input;
getline(std::cin, input);
vector<string> inputs{parse_input(input)};


d23384 (8) No.5156>>5157

>>5132

One other note. It occurs to me now that your approach is senstive to consecutive input values. If you'd prefer it to be insensitive, then add a sort() against the vector before calling the ranking code.

  // in the case of strings, the standard operator '<' is fine.
sort(begin(ret), end(ret));

Now, inputs such as

cow how now cow cow now now brown cow cow now
will still give you the same results.

So, this new variation would look like this:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <numeric>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

using std::adjacent_difference;
using std::begin;
using std::cout;
using std::end;
using std::getline;
using std::make_pair;
using std::pair;
using std::sort;
using std::string;
using std::stringstream;
using std::vector;

vector<string> parse_sorted_input(const string& input) {
stringstream input_ss;
input_ss << input; // load the stringstream

// Load a vector with whitespace-separated strings
vector<string> ret;
string tmp;
while (input_ss >> tmp) ret.emplace_back(tmp);

// in the case of strings, the standard operator '<' is fine.
sort(begin(ret), end(ret));

return ret; // rvo w/ vector
}

int main() {
string input;
getline(std::cin, input);
vector<string> inputs{parse_sorted_input(input)};

// track repetition counter, ranked by frequency
int cntr{0};
pair<int, string> ans = make_pair(0, "");
adjacent_difference(inputs.begin(), inputs.end(), inputs.begin(),
[&](string a, string b) {
if (a == b) {
++cntr;
ans = (cntr > ans.first) ? make_pair(cntr, a) : ans;
} else
cntr = 0;
return a;
});

if (ans.first > 0)
cout << "Found word '" << ans.second << "' with " << ans.first + 1
<< " consecutive occurrences.\n";
else
cout << "No duplicates found.\n";
}

/*
Sample input:
how now now now now brown cow cow cow cow cow
cow how now cow cow now now brown cow cow now

Sample output:
Found word 'cow' with 5 consecutive occurrences.
*/

https://en.cppreference.com/w/cpp/algorithm/sort


d23384 (8) No.5157

>>5156

In the output the term 'consecutive' is no longer needed ofc.


d23384 (8) No.5159>>5160

In thinking over your approach, I further realized you were using an algorithm that was designed to mutate the original container, but you weren't doing so, just keeping 'score'. std::for_each() seemed like a better fit, but it only offers a unary predicate, and what you need is a binary one. Looking around and not being able to find a standard library algorithm to fit (non-mutating, binary predicate) I pieced together one myself that satisfies. So here's my new version of your code that cuts out the wasted cycles in the score-keeping:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <numeric>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

// using std::adjacent_difference;
using std::begin;
using std::cout;
using std::end;
using std::getline;
using std::make_pair;
using std::pair;
using std::sort;
using std::string;
using std::stringstream;
using std::vector;

//------------------------------------------------------------------------------

template <class InputIt1, class BinaryOperation>
BinaryOperation walk_pairs(InputIt1 first1, InputIt1 last1,
BinaryOperation binary_op) {
while (first1 != last1) {
binary_op(*first1, *first1++);
}
return binary_op;
}

//------------------------------------------------------------------------------

// Load a vector with whitespace-separated strings from input
vector<string> parse_sorted_strings(const string& input) {
stringstream input_ss{input};
string tmp;
vector<string> ret;
while (input_ss >> tmp) ret.emplace_back(tmp);

sort(begin(ret), end(ret));

return ret; // RVO w/ vector
}

//------------------------------------------------------------------------------

int main() {
string input;
getline(std::cin, input);
vector<string> inputs{parse_sorted_strings(input)};

// track repetition counter, ranked by frequency
int cntr{0};
pair<int, string> ans = make_pair(0, "");

walk_pairs(begin(inputs), end(inputs), [&](const auto curr, const auto next) {
if (curr == next) {
++cntr;
ans = (cntr > ans.first) ? make_pair(cntr, curr) : ans;
} else
cntr = 0;
});

if (ans.first > 0)
cout << "Found word '" << ans.second << "' with " << ans.first + 1
<< " occurrences.\n";
else
cout << "No duplicates found.\n";
}

/*
Sample inputs:
how now now now now brown cow cow cow cow cow
cow how now cow cow now now brown cow cow now

Sample output:
Found word 'cow' with 5 consecutive occurrences.
*/

lol, thanks for the stimulation to think about this problem anon. this little library-tier snippet could be useful later.

also, why isn't this in the standard algorithms library already?


d23384 (8) No.5160

>>5159

probably better to name my template function 'for_each_pair()' instead tbh.

template <class InputIt, class BinaryOperation>
BinaryOperation for_each_pair(InputIt first, InputIt last,
BinaryOperation binary_op) {
while (first != last) {
binary_op(*first, *first++);
}
return binary_op;
}

>caller:

for_each_pair(begin(inputs), end(inputs),
[&](const auto curr, const auto next) {
if (curr == next) {
++cntr;
ans = (cntr > ans.first) ? make_pair(cntr, curr) : ans;
} else
cntr = 0;
});




[Return][Go to top][Catalog][Screencap][Nerve Center][Cancer][Update] ( Scroll to new posts) ( Auto) 5
17 replies | 0 images | 4 UIDs | Page ???
[Post a Reply]
[ / / / / / / / / / / / / / ] [ dir / arepa / hentai / hkpol / leftpol / s8s / shota / tulpa / vor ][ watchlist ]