How to negate a predicate function using operator ! in C++? - c++

I want to erase all the elements that do not satisfy a criterion. For example: delete all the characters in a string that are not digit. My solution using boost::is_digit worked well.
struct my_is_digit {
bool operator()( char c ) const {
return c >= '0' && c <= '9';
}
};
int main() {
string s( "1a2b3c4d" );
s.erase( remove_if( s.begin(), s.end(), !boost::is_digit() ), s.end() );
s.erase( remove_if( s.begin(), s.end(), !my_is_digit() ), s.end() );
cout << s << endl;
return 0;
}
Then I tried my own version, the compiler complained :(
error C2675: unary '!' : 'my_is_digit' does not define this operator or a conversion to a type acceptable to the predefined operator
I could use not1() adapter, however I still think the operator ! is more meaningful in my current context. How could I implement such a ! like boost::is_digit() ? Any idea?
Update
Follow Charles Bailey's instruction, I got this code snippet compiled, however the output is nothing:
struct my_is_digit : std::unary_function<bool, char> {
bool operator()( char c ) const {
return isdigit( c );
}
};
std::unary_negate<my_is_digit> operator !( const my_is_digit& rhs ) {
return std::not1( rhs );
}
int main() {
string s( "1a2b3c4d" );
//s.erase( remove_if( s.begin(), s.end(), !boost::is_digit() ), s.end() );
s.erase( remove_if( s.begin(), s.end(), !my_is_digit() ), s.end() );
cout << s << endl;
return 0;
}
Any idea what was wrong?
Thanks,
Chan

You should be able to use std::not1.
std::unary_negate<my_is_digit> operator!( const my_is_digit& x )
{
return std::not1( x );
}
For this to work you have to #include <functional> and derive your my_is_digit functor from the utility class std::unary_function< char, bool >. This is purely a typedef helper and adds no runtime overhead to your functor.
Complete working example:
#include <string>
#include <algorithm>
#include <functional>
#include <iostream>
#include <ostream>
struct my_is_digit : std::unary_function<char, bool>
{
bool operator()(char c) const
{
return c >= '0' && c <= '9';
}
};
std::unary_negate<my_is_digit> operator!( const my_is_digit& x )
{
return std::not1( x );
}
int main() {
std::string s( "1a2b3c4d" );
s.erase( std::remove_if( s.begin(), s.end(), !my_is_digit() ), s.end() );
std::cout << s << std::endl;
return 0;
}

How could I implement such a ! like boost::is_digit()
...presumably you could look at the code that forms the is_digit implementation? You will see predicate_facade and the relevant code:
template<typename PredT>
inline detail::pred_notF<PredT>
operator!( const predicate_facade<PredT>& Pred )
{
// Doing the static_cast with the pointer instead of the reference
// is a workaround for some compilers which have problems with
// static_cast's of template references, i.e. CW8. /grafik/
return detail::pred_notF<PredT>(*static_cast<const PredT*>(&Pred));
}

Related

how to add lambda function or perform custom operation in STL set in c++

I need a set arranges the value in such a way that if the int values are different i need the lexographically greater string to come front else i want the smaller integer to come front
set<pair<int,string>,[&](auto &a,auto &b){
if(a.first==b.first)return a.second>b.second;
return a.first<b.first;
}>;
It seems you mean the following
#include <iostream>
#include <string>
#include <utility>
#include <set>
#include <tuple>
int main()
{
auto less = []( const auto &p1, const auto &p2 )
{
return std::tie( p1.first, p2.second ) <
std::tie( p2.first, p1.second );
};
std::set<std::pair<int, std::string>, decltype( less )>
s( { { 1, "A" }, { 1, "B" }, { 2, "A" } }, less );
for ( const auto &p : s )
{
std::cout << p.first << ' ' << p.second << '\n';
}
}
The program output is
1 B
1 A
2 A
You could use also the constructor without the initializer list
std::set<std::pair<int, std::string>, decltype( less )>
s( less );

how to display common character if the two letters is equal in vector

For example I have vector {'a','a','b','b','c'} and I want to get the most letters which is a and b but this code the output is a;
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int getMostFrequentElement(std::vector<char> &arr)
{
if (arr.empty())
return -1;
std::sort(arr.begin(), arr.end());
auto last_int = arr.front();
auto most_freq_int = arr.front();
int max_freq = 0, current_freq = 0;
for (const auto &i : arr) {
if (i == last_int)
++current_freq;
else {
if (current_freq > max_freq) {
max_freq = current_freq;
most_freq_int = last_int;
}
last_int = i;
current_freq = 1;
}
}
if (current_freq > max_freq) {
max_freq = current_freq;
most_freq_int = last_int;
}
return most_freq_int;
}
int main(){
std::vector<char> arr = {'a','a','b','b','c'};
char ret = getMostFrequentElement(arr);
std::cout << "Most frequent element = " << ret;
}
May I know why my output becomes a instead a and b?
input vector arr{'a','a','b','b','c'}
expected output is a and b
but my output is a
Your function returns only the first most frequent character as an integer in a sorted vector.
For starters the implementation of the function is not good. The function shall not sort the passed by reference vector. It is the owner of the vector decides whether to sort the vector before calling the function. The function shall not modify the passed to it vector.
If you want that the function would return all most frequent characters in a vector then you need to change the function essentially.
For example the function can look the following way as it is shown in the demonstrative program below.
#include <iostream>
#include <vector>
#include <map>
#include <iterator>
#include <algorithm>
std::vector<char> getMostFrequentElement( const std::vector<char> &v )
{
std::vector<char> result;
std::map<char, size_t> m;
for ( const auto &c : v ) ++m[c];
auto it = std::max_element( std::begin( m ), std::end( m ),
[]( const auto &p1, const auto &p2 )
{
return p1.second < p2.second;
} );
if ( it != std::end( m ) )
{
for ( const auto &p : m )
{
if ( p.second == it->second ) result.push_back( p.first );
}
}
return result;
}
int main()
{
std::vector<char> v = { 'a', 'a', 'b', 'b', 'c' };
auto result = getMostFrequentElement( v );
for ( const auto &c : result ) std::cout << c << ' ';
std::cout << '\n';
return 0;
}
The program output is
a b
The answer from Vlad is good and should be accepted.
I would like to show an additional, more "mordern" C++ solution.
The Function body is rather compact and consists only of 3 lines of code. It will count all occurences of char and sort it in decreasing order regarding the occurence.
So, the caller of this function can show all kind of information. In the example below, I show all topmost elements.
But all kind of other evaluations may be shown.
Please see:
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
#include <set>
#include <iterator>
#include <unordered_map>
// Writing some aliases to prevent later typing work and make the code a little bit more readable. ---------------------
using DataType = char;
using CounterType = unsigned int;
using Pair = std::pair<DataType, CounterType>;
using Counter = std::unordered_map<DataType, CounterType>;
using Data = std::vector<DataType>;
struct Comp { bool operator ()(const Pair& p1, const Pair& p2) const { return (p1.second == p2.second) ? p1.first<p2.first : p1.second>p2.second; } };
using CountedAndSorted = std::multiset<Pair, Comp>;
// ----------------------------------------------------------------------------------------------------------------------
CountedAndSorted getMostFrequentElement(Data& data) {
// Count
Counter counter{};
for (const char c : data) counter[c]++;
// Return counted and sorted result
return {counter.begin(), counter.end()};
}
// ------------------------
// Test/Driver code
int main() {
// Test Data
Data d = { 'a', 'a', 'b', 'b', 'c' };
// Calculate result
auto result = getMostFrequentElement(d);
// Show output
for (const auto& [c, count] : result) if (count == result.begin()->second) std::cout << c << ' ';
}

Template functions to check "is int"/"is double"/etc

I am a bit shaky with C++ template syntax, so I'm not sure if what I'm envisioning is possible, and if it is, I'm unclear on correct syntax.
I would like to implement template functions like template<int> bool is( std::string& ), template<double> bool is( std::string& ), etc. so that I can call is <int> (...) or is <double> (...) instead of isInt(...) or isDouble(...), etc. Is this possible? If so, how would you code the function signatures?
With my tenuous grasp of template syntax, my attempt was:
#include <iostream>
#include <cstdlib>
template<int>
bool is( std::string& raw )
{
if ( raw.empty() ) return false;
char* p;
int num = strtol( raw.c_str(), &p, 10);
return ( ( *p != '\0' ) ? false : true );
}
int main( int argc, char* argv[] )
{
std::string str("42");
std::cout << std::boolalpha << is <int> ( str ) << std::endl;
return 0;
}
This failed with the following errors:
>g++ -g main.cpp
main.cpp: In function ‘int main(int, char**)’:
main.cpp:16:51: error: no matching function for call to ‘is(std::string&)’
std::cout << std::boolalpha << is <int> ( str ) << std::endl;
^
main.cpp:5:6: note: candidate: template<int <anonymous> > bool is(std::string&)
bool is( std::string& raw )
^
main.cpp:5:6: note: template argument deduction/substitution failed:
My comment to your post withstanding, the way to do this easily is with a simple template that uses the std::istringstream class to parse:
template<typename T>
bool is(std::string const& raw) {
std::istringstream parser(raw);
T t; parser >> t;
return !parser.fail() && parser.eof();
}
The obvious caveat is that T must be default constructable. But on the plus side, the above will work for user defined types as well, so long as they implement operator >>.
You need to use template specialisation for this:
#include <iostream>
#include <cstdlib>
template<class T> bool is(std::string& raw) = delete;
template<>
bool is<int>( std::string& raw )
{
if ( raw.empty() ) return false;
char* p;
int num = strtol( raw.c_str(), &p, 10);
return ( ( *p != '\0' ) ? false : true );
}
int main( int argc, char* argv[] )
{
std::string str("42");
std::cout << std::boolalpha << is <int> ( str ) << std::endl;
return 0;
}
You can read more about in here

Changing all elements in vector(list, deque...) using C++11 Lambda functions

I have the following code:
#include <iostream>
#include <vector>
#include <algorithm>
int main( int argc, char* argv[] )
{
std::vector< int > obj;
obj.push_back( 10 );
obj.push_back( 20 );
obj.push_back( 30 );
std::for_each( obj.begin(), obj.end(), []( int x )
{
return x + 2;
} );
for( int &v : obj )
std::cout << v << " ";
std::cout << std::endl;
return 0;
}
The result is : 10, 20, 30
i want to change all elements in vector (obj), using Lambda functions of new C++11 standard.
This is the code of implementation for_each function:
template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f)
{
for ( ; first!=last; ++first )
f(*first);
return f;
}
*first passed by value and cope of element is changed, what is the alternative of for_each i must use that i have a result: 12, 22, 32 ?
i want to change all elements in vector (obj), using Lambda functions of new C++11 standard.
You've to do this :
std::for_each( obj.begin(), obj.end(), [](int & x)
{ //^^^ take argument by reference
x += 2;
});
In your (not my) code, the return type of the lambda is deduced as int, but the return value is ignored as nobody uses it. That is why there is no return statement in my code, and the return type is deduced as void for this code.
By the way, I find the range-based for loop less verbose than std::for_each for this purpose:
for( int &v : obj ) v += 2;
You should use transform:
std::transform( obj.begin(), obj.end(), obj.begin(), []( int x )
{
return x + 2;
} );
Pass the argument by reference and modify the reference:
std::for_each( obj.begin(), obj.end(), [](int & x){ x += 2; } );
// ^^^^^
std::for_each( obj.begin(), obj.end(), []( int& x )
{
x += 2;
} );
In addition to the already existing (and perfectly correct) answers, you can also use your existing lambda function, that returns the result instead of modifying the argument, and just use std::transform instead of std::for_each:
std::transform(obj.begin(), obj.end(), obj.begin(), []( int x )
{
return x + 2;
} );

Case insensitive std::set of strings

How do you have a case insensitive insertion Or search of a string in std::set?
For example-
std::set<std::string> s;
s.insert("Hello");
s.insert("HELLO"); //not allowed, string already exists.
You need to define a custom comparator:
struct InsensitiveCompare {
bool operator() (const std::string& a, const std::string& b) const {
return strcasecmp(a.c_str(), b.c_str()) < 0;
}
};
std::set<std::string, InsensitiveCompare> s;
You may try stricmp or strcoll if strcasecmp is not available.
std::set offers the possibility of providing your own comparer (as do most std containers). You can then perform any type of comparison you like. Full example is available here
This is a generic solution that also works with other string types than std::string (tested with std::wstring, std::string_view, char const*). Basically anything that defines a range of characters should work.
The key point here is to use boost::as_literal that allows us to treat null-terminated character arrays, character pointers and ranges uniformly in the comparator.
Generic code ("iset.h"):
#pragma once
#include <set>
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <boost/range/as_literal.hpp>
// Case-insensitive generic string comparator.
struct range_iless
{
template< typename InputRange1, typename InputRange2 >
bool operator()( InputRange1 const& r1, InputRange2 const& r2 ) const
{
// include the standard begin() and end() aswell as any custom overloads for ADL
using std::begin; using std::end;
// Treat null-terminated character arrays, character pointers and ranges uniformly.
// This just creates cheap iterator ranges (it doesn't copy container arguments)!
auto ir1 = boost::as_literal( r1 );
auto ir2 = boost::as_literal( r2 );
// Compare case-insensitively.
return std::lexicographical_compare(
begin( ir1 ), end( ir1 ),
begin( ir2 ), end( ir2 ),
boost::is_iless{} );
}
};
// Case-insensitive set for any Key that consists of a range of characters.
template< class Key, class Allocator = std::allocator<Key> >
using iset = std::set< Key, range_iless, Allocator >;
Usage example ("main.cpp"):
#include "iset.h" // above header file
#include <iostream>
#include <string>
#include <string_view>
// Output range to stream.
template< typename InputRange, typename Stream, typename CharT >
void write_to( Stream& s, InputRange const& r, CharT const* sep )
{
for( auto const& elem : r )
s << elem << sep;
s << std::endl;
}
int main()
{
iset< std::string > s1{ "Hello", "HELLO", "world" };
iset< std::wstring > s2{ L"Hello", L"HELLO", L"world" };
iset< char const* > s3{ "Hello", "HELLO", "world" };
iset< std::string_view > s4{ "Hello", "HELLO", "world" };
write_to( std::cout, s1, " " );
write_to( std::wcout, s2, L" " );
write_to( std::cout, s3, " " );
write_to( std::cout, s4, " " );
}
Live Demo at Coliru
From what I have read this is more portable than stricmp() because stricmp() is not in fact part of the std library, but only implemented by most compiler vendors. As a result below is my solution to just roll your own.
#include <string>
#include <cctype>
#include <iostream>
#include <set>
struct caseInsensitiveLess
{
bool operator()(const std::string& x, const std::string& y)
{
unsigned int xs ( x.size() );
unsigned int ys ( y.size() );
unsigned int bound ( 0 );
if ( xs < ys )
bound = xs;
else
bound = ys;
{
unsigned int i = 0;
for (auto it1 = x.begin(), it2 = y.begin(); i < bound; ++i, ++it1, ++it2)
{
if (tolower(*it1) < tolower(*it2))
return true;
if (tolower(*it2) < tolower(*it1))
return false;
}
}
return false;
}
};
int main()
{
std::set<std::string, caseInsensitiveLess> ss1;
std::set<std::string> ss2;
ss1.insert("This is the first string");
ss1.insert("THIS IS THE FIRST STRING");
ss1.insert("THIS IS THE SECOND STRING");
ss1.insert("This IS THE SECOND STRING");
ss1.insert("This IS THE Third");
ss2.insert("this is the first string");
ss2.insert("this is the first string");
ss2.insert("this is the second string");
ss2.insert("this is the second string");
ss2.insert("this is the third");
for ( auto& i: ss1 )
std::cout << i << std::endl;
std::cout << std::endl;
for ( auto& i: ss2 )
std::cout << i << std::endl;
}
Output with case insensitive set and regular set showing the same
ordering:
This is the first string
THIS IS THE SECOND STRING
This IS THE Third
this is the first string
this is the second string
this is the third