STL sort function in C++ wrt strings - c++

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;
}
};

Related

Different ways of using a comparator in 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.

Error when I try to delete a value from a vector of structure based on one of its fields

I have the following structure:
struct Arrays {
std::string identifier;
size_t bits;
int AllocatedSize;
int CurrentAdress;
int MaxItemsAdress;
};
And I have a vector that here:
std::vector<Arrays> ArrayList;
At certain times, I need to remove values from this vector if the "identifier" field of a vector value matches the argument sent to a function of which here is the prototype:
void DestroySomeArray(std::vector<std::string> arrays);
Except I get this error:
C2064 The term does not correspond to a function that takes 1
arguments
I used std::remove_if with a predicate, here is my entier code:
struct Arrays {
std::string identifier;
size_t bits;
int AllocatedSize;
int CurrentAdress;
int MaxItemsAdress;
};
std::vector<Arrays> ArrayList;
bool IdPredicat(const Arrays &item, std::string id) {
return (item.identifier == id);
}
void DestroySomeArray(std::vector<std::string> arrays) {
for (int i = 0; i < ArrayList.size(); ++i)
if (IdPredicat(ArrayList[i], arrays[i]))
ArrayList.erase(std::remove_if(ArrayList.begin(), ArrayList.end(), IdPredicat(ArrayList[i], arrays[i])), ArrayList.end());
}
I don't understand where the error comes from, and my debugger takes me into the "algorithm" file of the standard libraries. So I couldn't identify the origin of the error (except for the DestroySomeArray function of course).
What did I do wrong?
Why your code does not work ? Because you do not send a predicate to the std::remove_if function, you send the result of your predicate, which is a bool, not an unary function (or functor). It explains the error message.
Here's a solution without predicate :
void DestroySomeArray(std::vector<std::string> arrays) {
for (auto it = ArrayList.begin(); it != ArrayList.end();)
if(std::find(arrays.begin(), arrays.end(), (*it).identifier) != arrays.end())
{ ArrayList.erase(it); }
else
{ ++it;}
}
And with a predicate :
struct Pred{
Pred(std::vector<std::string> arrays) : m_arrays(arrays) {}
bool operator ()(const Arrays& a) {
return (std::find(m_arrays.begin(), m_arrays.end(), a.identifier) != m_arrays.end());
}
private:
std::vector<std::string> m_arrays;
};
void DestroyWithPredicate(std::vector<std::string> arrays)
{
auto it = std::remove_if(ArrayList.begin(), ArrayList.end(), Pred(arrays));
ArrayList.erase(it, ArrayList.end());
}
Note that if you directly give a predicate to your Destroy() function, you can write something like that, using different predicates;
Destroy(Predicate1(/* ... */));
Destroy(Predicate2(/* ... */));
Which is quite nice :)

sort on a class member got the error unresolved overloaded function type

class S {
public:
vector <int> ia;
int rank;
bool cmp(S const &s1, S const &s2) {
return (s1.rank > s2.rank);
}
void sort_on_rank() {
sort(ia.begin(), ia.end(), cmp);
}
};
This piece of code is trying to sort the vector on rank, but doesn't compile because of following error,
[Error] no matching function for call to 'sort(std::vector::iterator, std::vector::iterator, )'
Please help me on this and tell where is the problem.
From your program it seems you want to sort objects of S classes. In that case your vector should be like this : std::vector<S>.
Your cmp is a non-static member function of class S and hence std::sort cannot work with it. (Think about how will you use the function).
You can either overload < operator for your class or pass a stand-alone/static member function or you can use C++11 lambda expression.
Thus your class becomes:
class S {
public:
vector<S> ia;
int rank;
void sort_on_rank() {
sort(ia.begin(), ia.end(),
[] (S const &s1, S const &s2) {
return (s1.rank > s2.rank);
});
}
};
However if you want to merely sort vector containing int in descending order, just call std::sort with a C++11 lambda that returns lhs > rhs.
std::sort(ia.begin(), ia.end(), [](int x, int y) { return x > y; });
Your S::cmp() takes S, but S::ia's value type is int.

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.

compare function in lower bound

I have following structure
enum quality { good = 0, bad, uncertain };
struct Value {
int time;
int value;
quality qual;
};
class MyClass {
public:
MyClass() {
InsertValues();
}
void InsertValues();
int GetLocationForTime(int time);
private:
vector<Value> valueContainer;
};
void MyClass::InsertValues() {
for(int num = 0; num < 5; num++) {
Value temp;
temp.time = num;
temp.value = num+1;
temp.qual = num % 2;
valueContainer.push_back(temp);
}
}
int MyClass::GetLocationForTime(int time)
{
// How to use lower bound here.
return 0;
}
In above code I have been thrown with lot of compile errors. I think I am doing wrong here I am new to STL programming and can you please correct me where is the error? Is there better to do this?
Thanks!
The predicate needs to take two parameters and return bool.
As your function is a member function it has the wrong signature.
In addition, you may need to be able to compare Value to int, Value to Value, int to Value and int to int using your functor.
struct CompareValueAndTime
{
bool operator()( const Value& v, int time ) const
{
return v.time < time;
}
bool operator()( const Value& v1, const Value& v2 ) const
{
return v1.time < v2.time;
}
bool operator()( int time1, int time2 ) const
{
return time1 < time2;
}
bool operator()( int time, const Value& v ) const
{
return time < v.time;
}
};
That is rather cumbersome, so let's reduce it:
struct CompareValueAndTime
{
int asTime( const Value& v ) const // or static
{
return v.time;
}
int asTime( int t ) const // or static
{
return t;
}
template< typename T1, typename T2 >
bool operator()( T1 const& t1, T2 const& t2 ) const
{
return asTime(t1) < asTime(t2);
}
};
then:
std::lower_bound(valueContainer.begin(), valueContainer.end(), time,
CompareValueAndTime() );
There are a couple of other errors too, e.g. no semicolon at the end of the class declaration, plus the fact that members of a class are private by default which makes your whole class private in this case. Did you miss a public: before the constructor?
Your function GetLocationForTime doesn't return a value. You need to take the result of lower_bound and subtract begin() from it. The function should also be const.
If the intention of this call is to insert here, then consider the fact that inserting in the middle of a vector is an O(N) operation and therefore vector may be the wrong collection type here.
Note that the lower_bound algorithm only works on pre-sorted collections. If you want to be able to look up on different members without continually resorting, you will want to create indexes on these fields, possibly using boost's multi_index
One error is that the fourth argument to lower_bound (compareValue in your code) cannot be a member function. It can be a functor or a free function. Making it a free function which is a friend of MyClass seems to be the simplest in your case. Also you are missing the return keyword.
class MyClass {
MyClass() { InsertValues(); }
void InsertValues();
int GetLocationForTime(int time);
friend bool compareValue(const Value& lhs, const Value& rhs)
{
return lhs.time < rhs.time;
}
Class keyword must start from lower c - class.
struct Value has wrong type qualtiy instead of quality
I dont see using namespace std to use STL types without it.
vector<value> - wrong type value instead of Value
Etc.
You have to check it first before posting here with such simple errors i think.
And main problem here that comparison function cant be member of class. Use it as free function:
bool compareValue(const Value lhs, const int time) {
return lhs.time < time ;
}
class is the keyword and not "Class":
class MyClass {
And its body should be followed by semicolon ;.
There can be other errors, but you may have to paste them in the question for further help.
You just want to make compareValue() a normal function. The way you have implemented it right now, you need an object of type MyClass around. The way std::lower_bound() will try to call it, it will just pass in two argument, no extra object. If you really want it the function to be a member, you can make it a static member.
That said, there is a performance penalty for using functions directly. You might want to have comparator type with an inline function call operator:
struct MyClassComparator {
bool operator()(MyClass const& m0, MyClass const& m1) const {
return m0.time < m1.time;
}
};
... and use MyClassComparator() as comparator.