Different ways of using a comparator in C++ - c++

I saw two different answers in Leetcode using comparators:
why is the first Comp function defined outside of the class? Even when I bring Comp into the class, the Leetcode fails.
How are you able to use Comp with out the ()?
How come I often see compare in structs?
bool Comp(const string& a, const string& b) {
...
}
class Solution {
public:
vector<string> reorderLogFiles(vector<string>& logs) {
stable_sort(logs.begin(), logs.end(), Comp);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ here
return logs;
}
};
and then
struct CompareLogs
{
bool operator() (const string& str1, const string& str2)
{
...
}
};
vector<string> reorderLogFiles(vector<string>& logs) {
sort(letter_logs.begin(), letter_logs.end(), CompareLogs());
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ and here
return letter_logs;
}

why is the first Comp function defined outside of the class?
As long as your self-defined function fulfills the expected parameters, you can place it inside or outside the class.
Even when I bring Comp into the class, the Leetcode fails.
You need to add static to make it class-independent:
class Solution
{
public:
static bool Comp(const std::string& a, const std::string& b)
{
}
std::vector<std::string> reorderLogFiles(std::vector<std::string>& logs)
{
std::stable_sort(logs.begin(), logs.end(), Comp);
return logs;
}
};
How come I often see compare in structs?
I do not see any advantage here.
Finally, one advice: use std:: prefix, do not omit it. You will avoid future problems.

Related

C++: multimap custom comparator for object keys

Can I somehow use my own function for ordering the pairs in multimap? I have three classes CTimeStamp, CMail and CMailLog. And the thing is in the CMailLog I have
multimap<CTimeStamp, CMail> which I use because for this task I need solution which will be very fast for huge amounts of data and therefor I would need to somehow use method Compare from CTimeStamp when inserting into this multimap. The classes look something like this.
class CTimeStamp {
public:
int compare (const CTimeStamp &x) const;
...
}
class CMail {
...
}
class CMailLog {
public:
...
private:
multimap<CTimeStamp, CMail> logs;
}
I'm not sure how to do this or if it's even possible.
I would need to somehow use method Compare from CTimeStamp when inserting into this multimap
As from the std::multimap documentation, all you need is to either
provide a specialisation for std::less<CTimeStamp>
namespace std {
bool less<CTimeStamp>(const CTimeStamp& a, const CTimeStamp& b) {
return a.compare(b) < 0;
}
}
or
provide a custom comparator at the constructor:
CMailLog() :
logs([](const CTimeStamp& a, const CTimeStamp& b) { return a.compare(b) < 0; })
{}
I used a lambda expression in my last example for the constructor as I consider that's the shortest and most comprehensible form.
In fact any callable with the signature bool (const CTimeStamp&,const CTimeStamp&) would fit well.
You might also write a simple global function
bool foo(const CTimeStamp& a,const CTimeStamp& b) {
return a.compare(b) < 0;
}
or appropriate callable type
struct foo {
bool operator()(const CTimeStamp& a,const CTimeStamp& b) {
return a.compare(b) < 0;
}
};
and pass that one at the
multimap<CTimeStamp, CMail> logs;
in the constructor initializer list:
CMailLog() : logs(foo) {}
Callable struct version
CMailLog() : logs(foo()) {}

STL sort function in C++ wrt strings

So I've been trying to sort a string based on the frequency of its characters. However the online judge I've been using shows me the error
Line 17: invalid use of non-static member function 'bool olution::helper(char, char)'
Why is the call to my function wrong? I have used the sort() function before, but not to strings. Is my helper() function incorrect?
class Solution {
public:
unordered_map<char,int> freq;
bool helper(char c1,char c2){
if(freq[c1]>freq[c2]) return false;
else return true;
}
string frequencySort(string s) {
for(char c:s)
{
freq[c]++;
}
sort(s.begin(),s.end(),helper);
return s;
}
};
Use a lambda to capture this:
sort(s.begin(),s.end(),[this](auto a, auto b) -> bool { return helper(a,b); });
Why is the call to my function wrong? I have used the sort() function
before, but not to strings. Is my 'helper()' function incorrect?
Because helper is member function of Solution. When you do this
sort(s.begin(),s.end(),helper);
you are basically doing this
sort(s.begin(),s.end(),this->helper);
The 3rd parameter to sort needs to be a standalone function, a predicate, a functor or a lambda. It cannnot be a non-static member of a class
This code, cleaned up, works. Note the statics
class Solution {
public:
// using thread_local so that each thread
// has its own global variable.
static thread_local std::unordered_map<char, int> freq;
static bool helper(char c1, char c2) {
return (freq[c1]<freq[c2]);
}
std::string frequencySort(std::string s)
{
freq.clear();
for (char c : s)
++freq[c];
std::sort(s.begin(), s.end(), helper);
return s;
}
};
// definition
std::unordered_map<char, int> Solution::freq;
Member functions have a hidden parameter that becomes this. You need either expose the state more widely, or write a capturing lambda
Also a Compare predicate must return false if you are comparing a value to itself, yours does not.
class Solution {
public:
string frequencySort(string s) {
unordered_map<char,int> freq;
for(char c:s)
{
freq[c]++;
}
sort(s.begin(),s.end(),[&freq](char lhs, char rhs){ return freq[lhs] < freq[rhs]; });
return s;
}
};

std::set. Custom set of sets

Word.
I have a struct, containing a single field that I would like set to use for comparison and equivalence, and other fields as metadata:
struct read_tag{
unsigned int read_id; // want std::set to use this
int offset; // metadata
bool orientation; // metadata
};
I have a functor to do the job:
struct read_tag_compare {
bool operator() (const read_tag &a, const read_tag &b) const {
return a.read_id > b.read_id
}
};
and decl. the required set as
std::set<read_tag, read_tag_compare> block;
Everything so far compiles. The problem is below:
How do I make a set containing std::set<read_tag, read_tag_compare>. I want something like this:
std::set< std::set<read_tag, read_tag_compare> > blocks;
blocks.insert(a_block); // comp error
But this gives me a very large, and hard to decipher error.
I thought it would recursively check how the inner sets are compared and extend this to the outer sets. All one had to do is define the comparator for the inner most set.
For example
std::set<std:set<unsigned int>> set_o_sets;
works fine, without me having to define how to compare std::set<unsigned int>
Any help is mucho appreciated :D
The <-comparison on std::set uses std::lexicographical_compare without comparator, i.e. it just forwards to < on the element type. (This is a limitation of the standard library, since this is defined for all containers, not just the ordered-associative ones.) So what you need is a custom comparator for sets of sets that uses the correct overload of lexicographical comparison:
using read_tag_set = std::set<read_tag, read_tag_compare>;
struct read_tag_set_compare {
bool operator()(const read_tag_set &a, const read_tag_set &b) const noexcept {
return std::lexicographical_compare(a.begin(), a.end(),
b.begin(), b.end(), a.key_comp());
// ^^^^^^^^^^^^
}
};
Now use: std::set<read_tag_set, read_tag_set_compare>
The code shows why there isn't an obvious "fix" to the ordered associative containers that would make this "just work": If the containers use custom, stateful predicates, then it's not in general guaranteed that the members of two distinct containers can actually be compared with one another at all. All you know is that the elements within one container are comparable with that container's comparator. So when you're using a custom comparator, you better also say explicitly how two distinct containers relate, and you assert explicitly that it makes sense to compare two containers.
It compiled with no error with my g++-5.3.1 ubuntu..
#include<set>
#include<iostream>
using namespace std;
struct read_tag{
unsigned int read_id; // want std::set to use this
int offset; // metadata
bool orientation; // metadata
};
struct read_tag_compare {
bool operator() (const read_tag &a, const read_tag &b) const {
return a.read_id > b.read_id;
}
};
struct read_compare {
bool operator() (const set<read_tag, read_tag_compare> &a, const set<read_tag, read_tag_compare> &b) const {
return true;
}
};
int main()
{
set<read_tag, read_tag_compare> block;
set<set<read_tag, read_tag_compare>, read_compare> blocks;
blocks.insert(block)
}
Above was what I compiled.

How to create a set with my customized comparison in c++

Could someone explain me what is going on in this example here?
They declare the following:
bool fncomp (int lhs, int rhs) {return lhs<rhs;}
And then use as:
bool(*fn_pt)(int,int) = fncomp;
std::set<int,bool(*)(int,int)> sixth (fn_pt)
While the example for the sort method in algorithm library here
can do like this:
bool myfunction (int i,int j) { return (i<j); }
std::sort (myvector.begin()+4, myvector.end(), myfunction);
I also didn't understand the following:
struct classcomp {
bool operator() (const int& lhs, const int& rhs) const
{return lhs<rhs;}
};
this keyword operator (not being followed by an operator as in a op. overload)... what is the meaning of it? Any operator applied there will have that behavior? And this const modifier... what is the effect caused by it?
I was trying to make a set of C-style string as follows:
typedef struct
{
char grid[7];
} wrap;
bool compare(wrap w1, wrap w2)
{
return strcmp(w1.grid, w2.grid) == -1;
}
set <wrap, compare> myset;
I thought I could create a set defining my sorting function in a similar as when I call sort from algorithm library... once it didn't compile I went to the documentation and saw this syntax that got me confused... Do I need to declare a pointer to a function as in the first example i pasted here?
struct classcomp {
bool operator() (const int& lhs, const int& rhs) const
{return lhs<rhs;}
};
Defines a functor by overloading the function call operator. To use a function you can do:
int main() {
std::set <wrap, bool (*)(wrap,wrap)> myset(compare);
return 0;
}
Another alternative is to define the operator as a part of the wrap class:
struct wrap {
char grid[7];
bool operator<(const wrap& rhs) const {
return strcmp(this->grid, rhs.grid) == -1;
}
};
int main() {
wrap a;
std::set <wrap> myset;
myset.insert(a);
return 0;
}
You're almost there... here's a "fixed" version of your code (see it run here at ideone.com):
#include <iostream>
#include <set>
#include <cstring>
using namespace std;
typedef struct
{
char grid[7];
} wrap;
bool compare(wrap w1, wrap w2) // more efficient: ...(const wrap& e1, const wrap# w2)
{
return strcmp(w1.grid, w2.grid) < 0;
}
set <wrap, bool(*)(wrap, wrap)> myset(compare);
int main() {
wrap w1 { "abcdef" };
wrap w2 { "ABCDEF" };
myset.insert(w1);
myset.insert(w2);
std::cout << myset.begin()->grid[0] << '\n';
}
"explain [to] me what is going on in this example"
Well, the crucial line is...
std::set<wrap, bool(*)(wrap, wrap)> myset(compare);
...which uses the second template parameter to specify the type of function that will perform comparisons, then uses the constructor argument to specify the function. The set object will store a pointer to the function, and invoke it when it needs to compare elements.
"the example for the sort method in algorithm library..."
std::sort in algorithm is great for e.g. vectors, which aren't automatically sorted as elements are inserted but can be sorted at any time. std::set though needs to maintain sorted order constantly, as the logic for inserting new elements, finding and erasing existing ones etc. all assumes the existing elements are always sorted. Consequently, you can't apply std::sort() to an existing std::set.
"this keyword operator (not being followed by an operator as in a op. overload)... what is the meaning of it? Any operator applied there will have that behavior? And this const modifier... what is the effect caused by it?
operator()(...) can be invoked on the object using the same notation used to call a function, e.g.:
classcomp my_classcomp;
if (my_classcomp(my_int1, my_int_2))
std::cout << "<\n";
As you can see, my_classcomp is "called" as if it were a function. The const modifier means that the code above works even if my_classcomp is defined as a const classcomp, because the comparison function does not need to modify any member variables of the classcomp object (if there were any data members).
You almost answered your question:
bool compare(wrap w1, wrap w2)
{
return strcmp(w1.grid, w2.grid) == -1;
}
struct wrap_comparer
{
bool operator()(const wrap& _Left, const wrap& _Right) const
{
return strcmp(_Left.grid, _Right.grid) == -1;
}
};
// declares pointer to function
bool(*fn_pt)(wrap,wrap) = compare;
// uses constructor with function pointer argument
std::set<wrap,bool(*)(wrap,wrap)> new_set(fn_pt);
// uses the function directly
std::set<wrap,bool(*)(wrap,wrap)> new_set2(compare);
// uses comparer
std::set<wrap, wrap_comparer> new_set3;
std::sort can use either a function pointer or a function object (http://www.cplusplus.com/reference/algorithm/sort/), as well as std::set constructor.
const modifier after function signature means that function can't modify object state and so can be called on a const object.

How to make aliases of member function or variable of specific class(like an STL container)

When using a std::pair or std::map, we need to use "first" or "second" to access data. But the two variable name do not have clear meanings of what it really store for other co-workers that did not write this code. So if we can make aliases for "first" or "second", it would enhance much readability.
For example, the following code
static const std::map<std::string, std::pair<std::string, PFConvert>> COMM_MAP =
{ // keyword-> (caption, function)
{std::string("1"), {std::string("Big5 to Utf16LE"), &FileConvert_Big5ToUtf16LE}},
{std::string("2"), {std::string("Utf16LE to Utf8"), &FileConvert_Utf16LEToUtf8}},
{std::string("3"), {std::string("Utf8 to Big5"), &FileConvert_Utf8ToBig5}}
};
auto iterToExe = COMM_MAP.find(strTransType);
iterToExe->second.second();
The iterToExe->second.second(); has a truly bad readability.
So I try to use inherit to give aliases as following
template<typename PFComm>
class CCommContent : public std::pair<std::string, PFComm>
{
public:
std::string &strCaption = std::pair<std::string, PFComm>::first;
PFComm &pfComm = std::pair<std::string, PFComm>::second;
};
template<typename PFComm>
class CCommPair : public std::pair<std::string, CCommContent<PFComm>>
{
public:
std::string &strPattern = std::pair<std::string, CCommContent<PFComm>>::first;
CCommContent<PFComm> commContent = std::pair<std::string,CCommContent<PFComm>>::second;
};
template<typename PFComm>
class CCommMap : public std::map<std::string, CCommContent<PFComm>, std::less<std::string>, std::allocator<CCommPair<PFComm>>>
{};
But this comes to an another issue: I have to declare all the ctors, though i could call the base ctors, but it still not seems to be a smart method. I Just want to make aliases.
A simple way is to use macro ...... but it bypass the type checking. when using a nested structure, it may be a nightmare when debug.
Any advice or discussion would be appreciated.
Why not simply use your own struct with your own element names?
struct MyPair {
std::string strCaption;
PFComm pfComm;
};
With C++11 you can easily create new objects of it:
MyPair{std::string("Big5 to Utf16LE"), &FileConvert_Big5ToUtf16LE}}
And if you define your own operator<, you can have std::set work as a map:
bool operator<(const MyPair& a, const MyPair& b) {
return a.strCaption < b.strCaption;
}
typedef std::set<MyPair> MyPairMap;
Naturally, you can nest your custom structs to form more complex nested pairs, although in your case you might want to consider a flat triplet instead:
struct CommMapEntry {
std::string number;
std::string caption;
PFComm pfComm;
};
bool operator<(const MyPair& a, const MyPair& b) {
return a.number<b.number;
}
static const std::set<CommMapEntry> COMM_MAP;
How about some typedefs and accessor functions?
using CommEntry = std::pair<std::string, PFConvert>;
std::string const & getCaption(CommEntry const & e) { return e.first; }
PFConvert const & getFunction(CommEntry const & e) { return e.second; }
Now you can say:
auto it = COMM_MAP.find(strTransType);
if (it != COMM_MAP.end())
{
auto & c = getCaption(it->second);
auto & l = getLabel(it->second);
// ...
}
If you later change the details of the type, you just have adapt the accessor functions.
well, in c++11, we can using base::base in a derive class to use the base ctors. But note that vs2013 DO NOT compliant this. g++4.8 do.