Implementation of lower_bound on vector pairs - c++

I know we need to include some compare function in order to achieve this.
But not able to write for this one.
For example:
Elements of vector={(2,4),(4,2),(5,1),(5,3)}
to find=5
lower_bound() should return 2
code->
#define pp pair<int,int>
bool cmp(const pp &l,const pp &r) {
return l.first < r.first;
}
int main() {
vector<pp> v;
sort(v.begin(), v.end(), cmp);
int id=(int)(lower_bound(v.begin(), v.end(), ??) - v.begin());
}

Pairs (just like tuples) compare lexicographically anyway. You don't need to define any special comparators for this.
And since you're using lower_bound you'll be searching for the first element that does not compare less than the val you're searching, so you should use a min value as the second pair element. To sum up, all can be done in "two" lines of code :
sort(v.begin(),v.end());
auto id = distance(v.begin(), lower_bound(v.begin(),v.end(),
make_pair(5, numeric_limits<int>::min())) );
Some Notes :
Use std::distance to calculate the number of elements between two iterators
The return type of std::distance is an unsigned type. Unless you need negative indexing (Python like syntax for "count from the end" indexes) it's a good practice to keep your indexes unsigned.

Since you don't care about the second value of pp, just construct a temporary pp object with any value as the second element.
int id = std::lower_bound(v.begin(), v.end(), pp(5, 0), cmp) - v.begin();

I think you should compare the pairs as per definition of lower_bound
So,
typedef pair<int,int> pp;
//...
int id=(int)(lower_bound(v.begin(),v.end(),
pp(5,std::numeric_limits<int>::min())), //Value to compare
[](const pp& lhs, const pp& rhs) // Lambda
{
return lhs < rhs ; // first argument < second
}
) - v.begin()
);

You can use lower_bound on vector of pairs with custom compare operator .
You need to pass four arguments in that case like this :-
it1 = iterator position from where to search
it2 = iterator position till where to search
lower_bound (it1 ,it2 , finding_element, your_comparator )
auto myComp = [&](pair<int,string> e1, pair<int,string> e2) {
if(e1.second!=e2.second)
return e1.second<e2.second;
else
return e1.first<e2.first;
};
void Show_sample_code()
{
vector<pair<int,string>> data={{1, "sahil"}, {2, "amin"}};
sort(data.begin(), data.end(), myComp);
pair<int, string> p={1,"sahil"};
auto it=lower_bound( data.begin(), data.end(), p, myComp ) ;
if(it!=data.end())
cout<<"found at index="<<distance(data.begin(), it)<<endl;
else
cout<<"notfound"<<endl;
return;
}

Related

Pick random element subset from map

I have a map of elements:
std::map<char,int> values;
values['a']=10;
values['b']=30;
values['c']=50;
values['d']=70;
values['e']=90;
values['f']=100;
values['g']=120;
So I need to pick N elements from values as a map of pairs preferably (output format as well as input format).
I tried other different solutions from stackoverflow but they mostly applicable for vector not for any type of C++ 11 container or looks too complicated for me.
I need some more effective way than just random_shuffle which actually mutates C++ container.
Also it would be nice if this function would be applicable for any type of C++ container.
You could copy the keys of the std::map<char, int> into an std::vector<char>. Then, shuffle this vector with std::random_shuffleX. Finally, return num elements of the map: the ones whose keys are the num last keys in the vector:
std::vector<std::pair<char, int>> pick_random(const std::map<char, int>& m, size_t num)
{
std::vector<char> keys;
keys.reserve(m.size());
// copy the map's keys
std::transform(m.begin(), m.end(), std::back_inserter(keys),
[](const std::pair<const char, int>& p) {
return p.first;
}
);
// shuffle the keys
std::random_shuffle(keys.begin(), keys.end());
// number of elements to pick
num = std::min(num, m.size());
std::vector<std::pair<char, int>> res;
res.reserve(num);
// pick num elements
std::generate_n(std::back_inserter(res), num,
[&keys, &m]() {
auto it = m.find(keys.back());
keys.pop_back();
return *it;
}
);
return res;
}
The idea is to randomly shuffle the elements in the vector containing the keys (i.e., keys). Therefore, you shuffle the keys, which map to elements in the map. You use these randomly shuffled keys to obtain elements from the map in a random way.
Xor std::shuffle insted since std::random_shuffle has been deprecated in C++14 and removed in C++17.
std::sample is C++17, but you can implement it yourself pretty easily in C++11. For example, for forward iterators (and std::map iterator does satisfy this requirement) typical implementation relies on the selection sampling algorithm. Its description can be found in Vol.2. of Knuth's TAOCP, p.142.
Simplest implementation:
template<class Forw_it, class Out_it, class URBG>
void sample(Forw_it first, Forw_it last, Out_it out, std::ptrdiff_t n, URBG&& g) {
auto sz = std::distance(first, last);
n = std::min(n, sz);
while (n != 0) {
std::uniform_int_distribution<std::ptrdiff_t> d(0, --sz);
if (d(g) < n) {
*out++ = *first;
--n;
}
++first;
}
}
Usage example:
std::map<char, int> values;
// ... assign values ...
std::vector<std::pair<char, int>> vec;
sample(values.begin(), values.end(), std::back_inserter(vec), 4, std::mt19937{});
for (auto p : vec)
std::cout << p.first << ' ' << p.second << '\n';
Sample output:
b 30
e 90
f 100
g 120
Full demo

How to add distinct pairs into a set?

I am trying to insert a few pairs of int into a set, these pairs don't have any order; that is, (1,2) = (2,1). So simply I do as follows,
typedef pair<int, int> pairs;
set<pairs> Set;
pair <int,int> myPair;
// adding pairs:
myPair=pair<int,int>(0,1);
pathSet.insert(myPair);
myPair=pair<int,int>(0,2);
pathSet.insert(myPair);
myPair=pair<int,int>(1,0);
pathSet.insert(myPair);
So I end up a set like
(0,1), (0,2) , (1,0)
I want to have
(0,1), (0,2)
How can I avoid duplicate? Is there any way? Is there any better ADT like std::unordered_set in terms of efficiency in comparison with 'set'?
You'll need a custom comparison function. In there, make sure that the order of the elements in a pair do not matter when comparing. A simple way would be to let the first element in the pair always be the smaller one (and exchange first and second otherwise).
The code could look like as follows:
int main() {
typedef pair<int, int> pairs;
auto cmp = [](pairs a, pairs b) {
if (a.first > a.second) {
swap(a.first, a.second);
}
if (b.first > b.second) {
swap(b.first, b.second);
}
return a < b;
};
set<pairs, decltype(cmp)> pathSet(cmp);
pairs myPair=pair<int,int>(0,1);
pathSet.insert(myPair);
myPair=pair<int,int>(0,2);
pathSet.insert(myPair);
myPair=pair<int,int>(1,0);
pathSet.insert(myPair);
cout << pathSet.size();
}
Output:
2
You need a custom compare function for std::set as you are using a std::pair as template type. In C++11, you can make it as a lambda as well.
The idea of compare function is to first check if the Pair is Pair.first < Pair.second, if not, swap to make them in order inside the compare function. This will not change the order of original inserted pair elements, but remove the duplicates as you mentioned.
auto compare = [](pairs lhs, pairs rhs)
{
if(lhs.first > lhs.second ) lhs = pairs{lhs.second, lhs.first };
if(rhs.first > rhs.second ) rhs = pairs{rhs.second, rhs.first };
return lhs< rhs;
};
Something like this: See live here
#include <iostream>
#include <set>
typedef std::pair<int, int> pairs;
int main()
{
auto compare = [](pairs lhs, pairs rhs) //custom compare lambda function
{
if(lhs.first > lhs.second ) lhs = pairs{lhs.second, lhs.first };
if(rhs.first > rhs.second ) rhs = pairs{rhs.second, rhs.first };
return lhs< rhs;
};
std::set<pairs, decltype(compare)> Set(compare);
Set.emplace(std::make_pair(0,1)); // use can also emplace to the Set
Set.emplace(pairs{0,2});
Set.emplace(pairs{1,0});
for(const auto& it: Set)
std::cout << it.first << " " << it.second << std::endl;
}
Output:
0 1
0 2

lower_bound on a vector of pair after checking one value of pair

I have a vector of pairs vector< pair< string,int> > in C++ and i want to lower_bound on string value but with additional constraint that the second value of pair should be less than or equal to a given value.
Currently i am doing it using a compare template
bool compare(const T &a,const T &b){
if (a.first<=b.first&&b.second<=a.second) return true;
}
but it is not working properly.
The vector is sorted according to the first value of pair.
Example->The vector has following contents:
abcd,1
abcde,4
abcdex,3
abce,2
and i want to lower_bound on abc,3 so it should return abcd,1 but it is returning abcdex,3.Please help.
std::lower_bound belongs to binary search algorithum family, where the elements are compared using operator< for
the first version, and comp for the second. The elements in the range
shall already be sorted according to this same criterion (operator< or comp), or at least partitioned with respect to val.
That means, you need to sort the vector as you mentioned in the way first, in order to act std::lower_bound as you expect.
Once you have sorted your vector of array in the way, you mentioned using a compare functor/ (I made it as a lambda), you can use std::lower_bound.
SEE LIVE HERE
#include <vector>
#include <iostream>
#include <algorithm>
int main()
{
using Pair = std::pair< std::string, int> ;
std::vector< Pair > vec =
{
{"abcd", 1},
{"abcde", 4},
{"abcdex", 3},
{"abce", 2}
};
// define the compare lambda/ functor accordingly
auto compare = [](const Pair &lhs, const Pair &rhs)->bool
{ return (rhs.second > lhs.second) ? false: lhs.first <= rhs.first; };
// sorted the vector according to the custom compare
std::sort(vec.begin(), vec.end(), compare);
auto getLower = std::lower_bound(vec.begin(), vec.end(), Pair("abc",3), compare);
if(getLower != vec.cend()) std::cout << getLower->first << " " << getLower->second;
return 0;
}
Output:
abcd 1
NOTE: In order to use std::lower_bound, you need to sort your vector according to the way you wanna apply lower bound first(which is the basic).
However, in your sorting pattern, std::lower_bound does not know the second value of the pair(int) weather the array is properly sorted or not. In other words, even if you sort accordingly what you mentioned beforehand, std::lower_bound can not give you the desired result, as you sort the Pairs in such a way that Pair.first and Pair.second in opposite order.
Therefore, I suggest you to use std::find_if, which will linearly search for elements and have to use the same compare funtor as the predicate. If the vector is sorted accordingly beforehand (as you mentioned), then it should give you a proper result.
// sort before
checkPair = Pair("abc",3);
auto getLower = std::find_if( vec.begin(), vec.end(), [&checkPair](const Pair &ele) -> bool
{
if(currPair == ele ) return true;
return (checkPair.first >= ele.first //--> "whose value is greater than or equal to the given string
&& ele.second < checkPair.second); //--> second value is less than a number
});
(getLower != vec.cend()) ?
std::cout << getLower->first << " " << getLower->second:
std::cout << "Nothing found";

Find last element in std::vector which satisfies a condition

I have this requirement to find the last element in the vector which is smaller than a value.
Like find_first_of but instead of first i want last.
I searched and found that there is no find_last_of but there is find_first_of.
Why is that so? Is the standard way is to use find_first_of with reverse iterators?
Use reverse iterators, like this:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{1,2,42,42,63};
auto result = std::find_if(v.rbegin(), v.rend(),
[](int i) { return i == 42; });
std::cout << std::distance(result, v.rend()) << '\n';
}
Live demo.
This is how it is done with reverse iterators:
std::vector<int> vec = {2,3,10,5,7,11,3,6};
//below outputs '3':
std::cout << *(std::find_if(vec.rbegin(), vec.rend(), [](int i) { return i < 4; }));
Just one thing. Be careful with the predicate if you're looking to find the tail-end of the range which includes the predicated element:
int main()
{
std::vector<int> x { 0, 1, 2, 3, 4, 5 };
// finds the reverse iterator pointing at '2'
// but using base() to convert back to a forward iterator
// also 'advances' the resulting forward iterator.
// in effect, inverting the sense of the predicate to 'v >= 3'
auto iter = std::find_if(std::make_reverse_iterator(x.end()),
std::make_reverse_iterator(x.begin()),
[](auto& v) { return v < 3; }).base();
std::copy(iter,
x.end(),
std::ostream_iterator<int>(std::cout, ", "));
}
result:
3, 4, 5,
From ZenXml:
template <class BidirectionalIterator, class T> inline
BidirectionalIterator find_last(const BidirectionalIterator first, const
BidirectionalIterator last, const T& value)
{
for (BidirectionalIterator it = last; it != first;)
//reverse iteration: 1. check 2. decrement 3. evaluate
{
--it; //
if (*it == value)
return it;
}
return last;
}

STL algorithm to find all tuples with first element within a range

I have a list of tuple, the list was sorted based on the first element of the tuple but the second and last elements are in random order. Now I want to find all tuples with the first element within a range, i.e. return all tuples for (tuple.first>-X and tuple.first<X). Among all these returning tuples, I need to find the maximum and minimum value in the second element of the tuples. How can a STL algorithm implement this?
ListType::iterator itrFirst = std::find_if( ls.begin(), ls.end(), boost::bind( &TupleType::get< 0 >, _1 ) >= rangeStart );
ListType::iterator itrLast = std::find_if( itrFirst, ls.end(), boost::bind( &TupleType::get< 0 >, _1 ) > rangeEnd );
for( ;itrFirst != itrLast; ++itrFirst ) // Print keys for elements in range
std::cout << itrFirst->get<0>() << std::endl;
I presume boost:: can be replaced with std:: if you have a recent compiler ( I don't ).
Since it is already sorted, you can use equal_range to get a pair of iterators that delimit the range of "interesting" tuples:
It const begin = std::lower_bound(list.begin(), list.end(),
[X](Tuple const& t) {
return t.first > -X;
});
It const end = std::upper_bound(begin, list.end(),
[X](Tuple const& t) {
return t.first < X;
});
std::pair<It,It> const range = std::make_range(begin, end);
Then, you can simply iterate over this range, and register the minimum and maximum values that you see:
int min = INT_MAX, max = INT_MIN;
for (Tuple const& t: range) {
if (t.second < min) { min = t.second; }
if (t.second > max) { max = t.second; }
}
// min and max are correctly set
So... it's not a single STL algorithm.
Note: std::min_element and std::max_element do exist, but that would mean looping twice over the range, it's certainly feasible though.
Tuple const& min = *std::min_element(range.first, range.second,
[](Tuple const& left, Tuple const& right) {
return left.second < right.second;
});
Tuple const& max = *std::max_element(range.first, range.second,
[](Tuple const& left, Tuple const& right) {
return left.second < right.second;
});
// Or as noted by Vitali, slightly more efficient:
auto const minmax = std::minmax_element(range.first, range.second,
[](Tuple const& left, Tuple const& right) {
return left.second < right.second;
});
Tuple const& min = *minmax.first;
Tuple const& max = *minmax.second;
Note that it gives a tuple, and not the .second member.