How to use a functor instead of lambda function - c++

I was trying to solve a problem from Leetcode.
Problem description:
Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest element in the matrix.
Note that it is the kth smallest element in the sorted order, not the kth distinct element.
I solved it like this:
class Solution {
public:
int kthSmallest(std::vector<std::vector<int>>& matrix, int k) {
auto comp_gt = [&matrix](std::pair<int ,int> a, std::pair<int ,int> b)
{
return matrix[a.first][a.second] > matrix[b.first][b.second];
};
m = matrix.size();
if (m == 0) return 0;
n = matrix[0].size();
if (n == 0) return 0;
std::priority_queue<std::pair<int, int>,
std::vector<std::pair<int, int>>,
decltype(comp_gt)> min_heap(comp_gt);
for (int j = 0; j < n; ++j)
{
min_heap.emplace(0, j);
}
for (int i = 0; i < k-1; ++i)
{
int r = min_heap.top().first;
int c = min_heap.top().second;
min_heap.pop();
if (r != m - 1)
{
min_heap.emplace(r+1, c);
}
}
return matrix[min_heap.top().first][min_heap.top().second];
}
private:
int m;
int n;
};
This code works. However, when I tried to replace the lambda function with a functor, I wrote the functor like this:
class comp_gt
{
bool operator () (std::pair<int, int> a, std::pair<int, int> b, std::vector<std::vector<int>>& matrix)
{
return matrix[a.first][a.second] > matrix[b.first][b.second];
}
};
then I realized I didn't know how to pass the matrix to a functor like [&matrix] in a lambda function.
Can anyone help?

You need to pass the reference in the constructor of the functor. Note that the below code is equivalent to your lambda, but with the mutable modifier.
class comp_gt
{
public:
using Matrix = std::vector<std::vector<int>>;
comp_gt(Matrix& matrix) : matrix{matrix}{}
bool operator () (std::pair<int, int> a, std::pair<int, int> b, std::vector<std::vector<int>>& matrix)
{
return matrix[a.first][a.second] > matrix[b.first][b.second];
}
private:
Matrix& matrix;
};
Then use it as:
comp_gt comp{matrix};

"How to use a functor instead of lambda function" - Create a class with operator() (that optionally captures variables). A lambda is nothing but syntactic sugar (an easier way) to write such a (functor) class.

This is done by passing it to the comparator's constructor:
class comp_gt
{
std::vector<std::vector<int>>& matrix;
comp_gt(std::vector<std::vector<int>>& matrix) : matrix{matrix} {}
Now, your existing operator() can use it normally.
Then, when you actually go about constructing the comparator, you just construct it normally and pass the appropriate parameter to the constructor. Let's say you wanted to use your comparator with std::sort:
comp_gt comparator{some_matrix};
std::sort(something.begin(), something.end(), comparator);
Using this comparator with std::priority_queue is analogous.

Related

passing a vector pair of integers into some function

This is the problem statement:
Given an array of integers nums, sort the array in increasing order based on the frequency of the values. If multiple values have the same frequency, sort them in decreasing order.
Return the sorted array.
Below is the implementation of my code.
Can anyone help me figure out the way to pass these pair of integers into the second function?
class Solution {
public:
bool sortByVal(const pair<int,int>&a,const pair<int,int>&b)
{
if(a.second==b.second)
return a.first<b.first;
return a.second>b.second;
}
vector<int> frequencySort(vector<int>&a) {
int n=a.size();
vector<int>res;
unordered_map<int, int> m;
vector<pair<int, int> > v;
for (int i = 0; i < n; ++i) {
m[a[i]]++;
}
copy(m.begin(), m.end(), back_inserter(v));
sort(v.begin(), v.end(), sortByVal);
for (int i = 0; i < v.size(); ++i)
while(v[i].second--)
{
res.push_back(v[i].first);
}
return res;
}
};
Here is the link of the problem on leetcode:
https://leetcode.com/problems/sort-array-by-increasing-frequency/
Make sortByVal to be static member function.
If you want to stay with non-static version, you have to wrap this function into callable object passing this pointer - required to call a member function for object. Use bind, or bind_front (since c++20):
sort(v.begin(), v.end(), std::bind(&Solution::sortByVal,this,std::placeholders::_1,std::placeholders::_2));
sort(v.begin(), v.end(), std::bind_front(&Solution::sortByVal,this));
Demo

How to sort std::set of indices according to the vector of sorted indices?

I have a class MyClass, which operates with some double values beta, stored as a class member, in it's member function g. It sorts them and stores the permutation in the class member std::vector<int> sorted_beta_ind:
double MyClass::g() {
// ...
sorted_beta_ind.resize(n);
for(unsigned int i=0; i<n; ++i) {
sorted_beta_ind[i] = i;
}
std::sort(sorted_beta_ind.begin(), sorted_beta_ind.end(),
[this] (const int &a, const int &b) {++op_cmp; return beta[a] > beta[b];});
// ...
}
Next I want to have several ordered sets of indices in another member function f, which will store the indices in the same order as in sorted_beta_ind. I'm trying to use std::set objects, and as such, I need a comparator. The best solution I figured out is a lambda function
double MyClass::f() {
auto ind_comp = [&order = sorted_beta_ind] (const int &a, const int &b) {
int pos_a = ~0, pos_b = ~0;
for(unsigned int i=0; i<order.size(); ++i) {
if(order[i] == a) {
pos_a = i;
}
if(order[i] == b) {
pos_b = i;
}
}
return pos_a < pos_b;
};
std::set<int, decltype(ind_comp)> d0, d1;
// the rest of the function which uses std::union and std::instersection
}
but on building the project I get
error: use of deleted function ‘MyClass::f()::<lambda(const int&, const int&)>& MyClass::f(int**, int)::<lambda(const int&, const int&)>::operator=(const MyClass::f()::<lambda(const int&, const int&)>&)’
Can this approach work or I should try something entirely else?
Capturing lambda expressions, like yours, are not DefaultConstructible. And that's exactly what std::set tries to do unless it receives a comparator object that can be copied from as a constructor call argument. That is:
std::set<int, decltype(ind_comp)> d0, d1;
Here std::set knows only the type of the comparator, and will attempt to constuct one using its default constructor. Instead, it should be:
std::set<int, decltype(ind_comp)> d0(ind_comp), d1(ind_comp);
// ~~~~~~~^ ~~~~~~~^

STL priority_queue of pairs<int, struct> error

Finding a shortest path in a grid and struggling to set up priority queue properly.
struct position{
int row;
int col;
position* parent;
position(int a, int b):row(a),col(b), parent(nullptr){}
};
vector<position>vec;
priority_queue<pair<int, position>, vector<pair<int, position>>, greater<pair<int, position>>>pq;
int distance = 0;
position *t = new p(0,0);
pq.push(make_pair(distance, t));
Getting this error:
no matching function for call to ‘std::priority_queue, std::vector >, std::greater > >::push(std::pair)’
pq.push(make_pair(distance, t));
You need to write a functor ( or use a lambda) to compare the distance - position pair, std::greater won't automatically do it for you. Try this snippet:
struct position {
int row;
int col;
position* parent;
position(int a, int b) :row(a), col(b), parent(nullptr) {}
};
typedef std::pair<int, position> dist_pos_t;
class compare
{
public:
bool operator()(const dist_pos_t& lhs, const dist_pos_t& rhs)
{
return rhs.first < lhs.first;
}
};
std::priority_queue<dist_pos_t, std::vector<dist_pos_t>, compare >pq;
int main() {
int distance = 0;
position *t = new position(0, 0);
pq.push(std::make_pair(distance, *t));
}
Here Declaration of Priority Queue does not match with what you are trying to push.
Declaration should be something like
priority_queue<pair<obj1,obj2>pq;
obj1/obj2 can be anything like int or pair<obj,obj>
After such declaration you can use
pq.push(make_pair(obj1,obj2))
There are two major issues in your code.
First, your priority_queue is of std::pair<int, position>, but you are trying to push in a std::pair<int, position*>.
Second, std::greater<T> depends on the > operator of the underlying type T. In your case, it's std::pair<int, position>, whose > operator depends on the < operator of position (See this reference). You need to provide < for position, or, you can use a custom compare functor type.

use n_th element in a container, but with another key

I have two vectors. One that actually holds the data (let's say floats) and one that holds the indices. I want to pass at nth_element the indices vector, but I want the comparison to be done by the vector that actually holds the data. I was thinking about a functor, but this provides only the () operator I guess. I achieved that by making the data vector a global one, but of course that's not desired.
std::vector<float> v; // data vector (global)
bool myfunction (int i,int j) { return (v[i]<v[j]); }
int find_median(std::vector<int> &v_i)
{
size_t n = v_i.size() / 2;
nth_element(v_i.begin(), v_i.begin()+n, v_i.end(), myfunction);
return v_i[n];
}
You may use a functor like:
class comp_with_indirection
{
public:
explicit comp_with_indirection(const std::vector<float>& floats) :
floats(floats)
{}
bool operator() (int lhs, int rhs) const { return floats[lhs] < floats[rhs]; }
private:
const std::vector<float>& floats;
};
And then you may use it like:
int find_median(const std::vector<float>& v_f, std::vector<int> &v_i)
{
assert(!v_i.empty());
assert(v_i.size() <= v_f.size());
const size_t n = v_i.size() / 2;
std::nth_element(v_i.begin(), v_i.begin() + n, v_i.end(), comp_with_indirection(v_f));
return v_i[n];
}
Note: with C++11, you may use lambda instead of named functor class.
int find_median(const std::vector<float>& v_f, std::vector<int> &v_i)
{
assert(!v_i.empty());
assert(v_i.size() <= v_f.size());
const size_t n = v_i.size() / 2;
std::nth_element(
v_i.begin(), v_i.begin() + n, v_i.end(),
[&v_f](int lhs, int rhs) {
return v_f[lhs] < v_f[rhs];
});
return v_i[n];
}

sort one array and other array following?

here is the C++ sample
int a[1000] = {3,1,5,4}
int b[1000] = {7,9,11,3}
how do i make it so if i sort array a, array b also following array a
example
a[1000] = {1,3,4,5}
b[1000] = {9,7,3,11}
is it possible using sort function
sort(a,a+4)
but also sort array b aswell ?
edit: what if there are 3 arrays ?
Instead of using two arrays, can you use an array of pairs and then sort THAT using a special comparison functor rather than the default less-than operator?
The simplest way is to rearrange your data into an array-of-structs instead of a pair of arrays so that each datum is contiguous; then, you can use an appropriate comparator. For example:
struct CompareFirst
{
bool operator() (const std::pair<int,int>& lhs, const std::pair<int,int>& rhs)
{
return lhs.first < rhs.first;
}
};
// c[i].first contains a[i], c[i].second contains b[i] for all i
std::pair<int, int> c[1000];
std::sort(c, c+1000, CompareFirst());
If you can't refactor your data like that, then you need to define a custom class that acts as a RandomAccessIterator:
struct ParallalArraySortHelper
{
ParallelArraySortHelper(int *first, int *second)
: a(first), b(second)
{
}
int& operator[] (int index) { return a[index]; }
int operator[] const (int index) { return a[index]; }
ParallelArraySortHelper operator += (int distance)
{
a += distance;
b += distance;
return *this;
}
// etc.
// Rest of the RandomAccessIterator requirements left as an exercise
int *a;
int *b;
};
...
int a[1000] = {...};
int b[1000] = {...};
std::sort(ParallalArraySortHelper(a, b), ParallelArraySortHelper(a+1000, b+1000));
Generate an array the same size as the original, containing the indexes into the array: {0, 1, 2, 3}. Now use a custom comparator functor that compares the elements in an associated array rather than the indexes themselves.
template<typename T>
class CompareIndices
{
public:
CompareIndices(const T * array) : m_AssociatedArray(array) {}
bool operator() (int left, int right) const
{
return std::less(m_AssociatedArray[left], m_AssociatedArray[right]);
}
private:
const T * m_AssociatedArray;
};
std::sort(i, i+4, CompareIndices(a));
Once you have a sorted list of indices, you can apply it to the original array a, or any other b array you want.