C++11 equal_to and less - c++

Code:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<typename T, typename C> T pfind(T f, T e, C c){
do{
for (int i = 1; f + i != e; i++)
if (c(*f, *f + i))
return (f + i);
} while (++f != e);
}
int main()
{
vector<int>vstr = { 1, 2, 3, 4,4,5,5,5 };
vstr.erase(pfind(vstr.begin(), vstr.end(),equal_to<int>()));
for (auto&itr : vstr){
cout << itr << " ";
}
getchar();
}
This code crashes...
But when i tried to use less instead of equal_to its working....
Could anyone please explain me why?

If you'd paid attention to the compiler warnings, you'd have had a clue why your function fails. When you pass std::equal_to as the comparison predicate, it's not finding a match (due to an error in your code).
In the case where a match isn't found, your function ends without returning anything, which is undefined behavior. The subsequent use of this non-existent return value in the call to vector::erase results in the crash.
Your code fails to find a match because of this condition:
if (c(*f, *f + i))
You're first dereferencing the iterator and then adding i to that result. What you actually want to do is
if (c(*f, *(f + i)))
And then add a return statement at the end of the function for the case when a match is not found.
return e; // return the end iterator
Finally, your entire function can be replaced by std::adjacent_find which searches a range for two adjacent elements that meet a specified criterion. The two argument version uses operator== to perform the comparison, while you can supply a binary predicate using the three argument version. Using this, your example reduces to
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int>vstr = { 1, 2, 3, 4,4,5,5,5 };
vstr.erase(std::adjacent_find(vstr.begin(), vstr.end()));
for (auto&itr : vstr) {
cout << itr << " ";
}
}
Output:
1 2 3 4 5 5 5
Live demo

So, in the comments Alessandro Teruzzi has the key point.
are you sure you meant c(*f,*f+i) instead of c(*f,*(f+i))?
But that being said, this could be written more clearly as two nested for loops, and with longer variable names.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<typename T, typename C> T pfind(T begin, T end, C comparator){
for (int i = 0; begin + i != end; ++i)
for (int j = i+1; begin + j != end; j++)
if (comparator(begin[i], begin[j]))
return (begin + i);
return end;
}
int main()
{
vector<int>vstr = { 1, 2, 3, 4,4,5,5,5 };
vstr.erase(pfind(vstr.begin(), vstr.end(),equal_to<int>()));
for (auto&itr : vstr){
cout << itr << " ";
}
getchar();
}
We could also write the pfind() function directly using iterators:
template<typename T, typename C> T pfind(T begin, T end, C comparator){
for (; begin != end; begin++)
for (T iterator = std::next(begin); iterator != end; iterator++)
if (comparator(*begin, *iterator))
return begin;
return end;
}
Additionally, in both cases there's a chance that we will return the end pointer. If we do, then we will call vstr.erase(vstr.end()), which is undefined behavior. So you probably want to check for that.
Let's talk about what a particular warning means:
In the comments you said that the compiler reported this warning:
main.cpp:13:1: warning: control may reach end of non-void function [-Wreturn-type]
It means that the compiler was not able to ensure that all paths through the code would end with a statement return ...; In your case, in the simplest case, if begin == end, then the first loop will not be entered, and we will hit the end of the function without reaching a return ...; statement.
In the code I've posted with fixes, you can see that if we never find a match, we return the end pointer, which is a common way of reporting no match.

Related

Capitalizing letters

I have got a small problem. I want to capitalize on doubled letters in a string. I managed to compile a program, but not successfully.
#include <iostream>
#include <cctype>
#include <string>
std::string::iterator function(
std::string::const_iterator a,
std::string::const_iterator b,
std::string::const_iterator e)
{
for (; a < b; a++)
{
if (*a == *(a + 1))
{
toupper(*a);
toupper(*(a + 1));
}
}
}
int main()
{
std::string in = "peppermint 1001 bubbles balloon gum", out(100, '*');
auto e = function(in.cbegin(), in.cend(), out.begin());
int n = e - out.begin();
std::string s = out.substr(0, n);
bool b = (s == "pePPermint 1001 buBBles baLLOOn gum");
std::cout << std::boolalpha << b << std::endl;
}
What do I do wrong?
You have a couple of issues there.
Firstly, your function promised to return std::string::iterator
std::string::iterator function(....)
{
//... return statement is missing here!
}
and you are not keeping the promise. This will leads to undefined behaviour. For example, in your case, it just compiles and does not give the output.
In order to get a defined behaviour, you should return from the function
std::string::iterator function(...)
{
// ... code
return {}; // return appropriately iterator of std::string
}
Secondly, you want to modify the characters of the string, which requires a modifiable iterator rather than std::string::const_iterator.
Then in the loop, you need to alter the capitalized charector by reassigning to it. For example:
*a = toupper(*a);
Thirdly, you should be careful about doing this in the for-loop of your function
for(; a < b; a++)
{
if(*a == *(a + 1)) // --->here
// ... code
}
What would happen for the case when a== str.end()-1, you still would do the increment(i.e. *(a + 1)), right?. Incrementing the end iterator again leads you Undefined behaviour.
In that case, you could use std::next from <iterator> header to safely check this.
Following is the demonstrative code which clears the issues mentioned above:
#include <iostream>
#include <string>
#include <iterator> // std::next
std::string::iterator function(
std::string::iterator a,
std::string::iterator b,
std::string::iterator e)
{
auto beg = a;
for (; a < b; a++)
{
if (std::next(a) != b && *a == *std::next(a)) {
*a = toupper(*a);
*std::next(a) = toupper(*std::next(a));
}
}
std::cout << std::string{ beg, b };
return {}; // return appropriately iterator of std::string
}
prints for now: https://godbolt.org/z/ZsLHxw
pePPermint 1001 buBBles baLLOOn gum
I assume that you want somehow to get the output to the third function parameter std::string::iterator e. I will let that part for you to figure it out. Meanwhile, have a look at the standard algorithm function std::transform, which might be handy to do such kind of transformation.
Answers are already given. I want additionally to show an answer based on existing C++ functionality. For your given task there is a function existing in the C++ standard algorithm library. It is called std::adjacent_find. Please see here.
With that you could rewrite your code simply to:
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
int main() {
std::string test{ "peppermint 1001 bubbles balloon gum" };
// Find all duplicates
for (auto il = std::adjacent_find(test.begin(), test.end()); il != test.end(); il = std::adjacent_find(il+1, test.end())) {
// If duplicate found, then convert both to uppercase
*il = std::toupper(*il);
*(il + 1) = std::toupper(*(il+1));
}
std::cout << test << '\n';
return 0;
}
We call this function in a simple for loop, until no more duplicates could be found.
Maybe it can give you an idea for a more simple implementation.
Your function exhibits undefined behavior because it never returns a value. Please compile with -Wall -Wextra to enable all compiler warnings to avoid such unnecessary bugs.

Is it possible to peek at the next element in a range-for loop?

Say I have this:
void test(std::vector<int>& my_ints) {
for (auto& my_int : my_ints) {
if (my_int == 5 && /* not the last value in the vector */) {
my_int += /* next value in the vector */;
}
}
}
Is there any valid syntax to replace the comments with?
PS! yes, i know, piece of cake with a regular for loop but I want to see if I can use range-for loops for this type of stuff.
Is it possible to peek at the next element
In general case - no.
Since objects in std::vector are stored contiguously, you could do *(&my_int + 1), but if you change the container later, the code might silently break. Don't do that!
And to check if the current element is the last one, you could use &my_int == &my_ints.back().
I can't think of a safe way to do what you want, with a ranged loop.
If you can bare an extra helper function, you could somehow generalize the algorithm you are using, though:
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
template <class Container, class BinaryOp>
void apply_using_the_next(Container& cc, BinaryOp op)
{
if (std::cbegin(cc) == std::cend(cc))
return;
std::transform(std::begin(cc), std::prev(std::end(cc)),
std::next(std::cbegin(cc)),
std::begin(cc), op);
}
void test(std::vector<int>& v)
{
apply_using_the_next(v, [] (const int a, const int b) {
return a == 5 ? a + b : a;
});
}
int main()
{
std::vector<int> a{2, 5, 4, 3, 5, 5, 1};
test(a);
for (auto const i : a) // -> 2 9 4 3 10 6 1
std::cout << ' ' << i;
std::cout << '\n';
}
Live, here.
You can use iterator.
for (std::vector<int>::iterator it = my_ints.begin(); it < my_ints.end() - 1; ++it) {
if (*it == 5 /* no need to check as iterating until second last value && it != my_ints.end() - 1*/) {
*it += *(it+1);
}
}
Even if the vector is empty, the loop won't enter as it < my_ints.end() - 1 will return false, so it is safe.

How to apply the concept of counting occurrences on strings variables in C++

following program ca calculate the frequency of ints in an array
how to apply this concept on string variable because a string is also an array on the back end
using namespace std;
int counter[10]={0,0,0,0,0,0,0,0,0,0};
int arr [9][9],x;
int main()
{
srand(time(NULL));
cout<<"enter the array \n";
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
arr[i][j]=rand()%10;
}
}
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
cout<<arr[i][j]<<" ";
}
cout<<endl;
}
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
counter[arr[i][j]]++;
}
}
for(int j=0;j<10;j++){
cout<<j<<" : "<< counter[j]<<endl;
}
return 0;
}
Here is how one can count occurrences of anything from anything:
Code
#include <iterator>
#include <map>
#include <algorithm>
template<class InputIt>
auto
occurrences(InputIt begin, InputIt end)
{
std::map<typename std::iterator_traits<InputIt>::value_type, std::size_t> result;
std::for_each(begin, end, [&result](auto const& item){ ++result[item]; });
return result;
}
Usage
#include <string>
#include <iostream>
int main()
{
auto text = std::string{"Hello, World!"};
auto occ = occurrences(begin(text), end(text));
std::cout << occ['l'] << '\n'; // outputs 3
}
Live demo
Explanation
template<class InputIt>
This is a generic (template) function iterating over any input iterator.
auto
Its return type is inferred from its implementation. Spoiler alert: it is a std::map of (value counter, occurrence of this value).
occurrences(InputIt begin, InputIt end)
occurrences is called with a couple of iterators defining a range, generally calling begin(C) and end(C) on your container C.
std::for_each(begin, end, //...
For each element in the range...
[&result](auto const& item){ //...
...execute the following treatment...
++result[item]; });
...increment the occurrence count for the value item, starting with zero if its the first.
This is not an efficient implementation since it copies the values it counts. For integers, characters, etc. its perfect but for complex types you might want to improve this implementation.
It's generic and standard container compatible. You could count anything iterable.
If I understand correctly, you want to count occurrences of strings. STL container map is useful for this purpose. Following is example code.
#include<iostream>
#include<map>
#include<string>
#include<vector>
int main()
{
std::vector<std::string> arrayString;
std::map<std::string, int> counter;
std::map<std::string, int>::iterator it;
arrayString.push_back("Hello");
arrayString.push_back("World");
arrayString.push_back("Hello");
arrayString.push_back("Around");
arrayString.push_back("the");
arrayString.push_back("World");
// Counting logic
for(std::string strVal : arrayString)
{
it = counter.find(strVal);
if(it != counter.end())
it->second += 1; // increment count
else
counter.insert(std::pair<std::string, int>(strVal, 1)); // first occurrence
}
// Results
for(std::map<std::string, int>::iterator it = counter.begin(); it != counter.end(); ++it)
std::cout << it->first << ": " << it->second << std::endl;
return 0;
}
More compact way to write the counting logic is :
// Counting logic
for(std::string strVal : arrayString)
{
++counter[strVal]; // first time -> init to 0 and increment
}

Difference between using ++ and +1 when use iterator

We all know if we want to increase iterator we can use operator "++" or use "+1". Is there have difference betwen ++ and +1?
Now, I run this program:
#include <iostream>
#include <string>
#include <iterator>
using namespace std;
int Str(string &s, string::iterator it)
{
if(it == s.end())
return 0;
else
{
return (1 + Str(s,it++)); // Wrong line of code.When using "it + 1"
//programme could get right result but
//when using "it++" programme could not
// get right result
}
}
int main(int argc, char* argv[])
{
string s;
cout << "enter: ";
cin >> s;
string::iterator it = s.begin();
int i = Str(s,it);
cout << "str= " << i << endl;
return 0;
}
I use iterator as a function parameter.
Not all iterators can do +1. Only random access iterators can do this. All iterators can do ++ though. But there are two versions of ++.
Then your mistake is that i++ computes i+1 but returns the previous value. What you want is ++i, returning the new incremented iterator.
The issue is that in
return (1 + Str(s, it++));
you are using the postfix increment operator, which performs the increment but returns the iterator in its state before the increment. You can change this to
return (1 + Str(s, ++it));
which should yield the desired result. Note that it + 1 works for random access iterators only. It does the same in your case, but you could try to enforce as little constraints as possible for the iterators in use, e.g., when you change your container to one that works with bidirectional iterators, it would be desirable that your code still works. I'd hence recommend going with ++it.
Note that there is also the function template std::next, which increments the given iterator. It is also quite readable to go with
return (1 + Str(s, std::next(it));

Finding most common element in a list (C++ STL)?

I have a program where I have to find the most common element in a list of integers. I do this with the program below, but the problem is, I suspect that the erase function messes up with the iterator incrementation in the countRepetition() function. My question is how can I fix the problem or if this is not the issue what is it?
Thanks in advance.
You have a couple issues. First, as you suspected, was the incorrect use of erase. When you erase an iterator it invalidates the iterator. Any use of the iterator afterwards is undefined behavior. Since erase returns the next valid iterator what you can do is restructure the loop like
for (START = l.begin(); START != l.end();) { // do not increment here
if (*START) {
counter++;
START = l.erase(START); // erase and get next
}
else
{
++START; // go to next
}
}
So now at least you loop through the list. Unfortunately you will still have an invalid iterator in main. You pass START from main to countRepetition and when that iterator is erased from the list you then have an invalid iterator. What you need to do is get a new begin iterator from the list each iteration since you are always erasing the first element. That would make your for loop look like
for (START = l.begin(); START != l.end(); START = l.begin()) {
m.push_back(countRepetition(START));
}
Another issue is you just check if the character is not 0. If you are counting repetitions you need to make sure you are checking that the iterator is the same character. I'll leave that for you to implement.
I would also like to point out there is an easier way to do all of this. A std::map lets you build a histogram very easily. Combine that with std::max_element and you could write your entire program as
int main()
{
std::map<char, int> histogram;
while ('0' != (number = getchar()))
++histogram[number]; // add to map, increment count of occurances
auto most_frequent = *std::max_element(histogram.begin(),
histogram.end(),
[](const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; }).first;
std::cout << most_frequent;
return 0;
}
Your problem is that you use global variables everywhere.
The global START is changed in two loops, so you only access the first loop once, then it is changed again in the second function and you don't execute the first loop a second time.
Why do you use the global variables? You should not use them but use local variables.
This is probably what you are looking for:
#include <iostream>
#include <list>
#include <vector>
#include <map>
using namespace std;
list <char> l;
map<char, int> ans;
int main()
{
char c;
do{
c = getchar();
l.push_back(c);
}while(c != '0');
for(auto chr: l){
ans[chr]++;
}
char ch;
int mx = 0;
for(auto k: ans){
if(k.second > mx)
{
ch = k.first;
mx = k.second;
}
}
cout<<ch<<" : "<<mx;
}