I need to create a lookup table which links a length to a time interval (both are of data type double). The keys increment linearly as they are inserted, so it will already be sorted (perhaps an unordered_map would be better?).
What I am looking for is a way to find a key that best matches the current length provided to get the time value, or even better find the two keys that surround the length (the given key is between them) so I can find the interpolated value between the two time values.
I also need the best performance possible as it will be called in real time.
EDIT: I would have rather the following was a comment to the first answer below, but the format is hard to read.
I tried to do the following, but it seems to return the same iterator (5.6):
std::map<double, double> map;
map.insert(std::pair<double, double>(0.123, 0.1));
map.insert(std::pair<double, double>(2.5, 0.4));
map.insert(std::pair<double, double>(5.6, 0.8));
std::map<double, double>::iterator low, high;
double pos = 3.0;
low = map.lower_bound(pos);
high = map.upper_bound(pos);
How would I get 'low' to point to the last element that is < than the key used to search?
EDIT 2:
Silly me, 'low--' will do it, providing it's not the first element.
Getting there :)
For this, you can use either std::map::lower_bound
Returns an iterator pointing to the first element that is not less than key.
or std::map::equal_range
Returns a range containing all elements with the given key in the container.
In your case, if you want the closest entry, you need to check both the returned entry and the one before and compare the differences. Something like this might work
std::map<double, double>::iterator low, prev;
double pos = 3.0;
low = map.lower_bound(pos);
if (low == map.end()) {
// nothing found, maybe use rbegin()
} else if (low == map.begin()) {
std::cout << "low=" << low->first << '\n';
} else {
prev = std::prev(low);
if ((pos - prev->first) < (low->first - pos))
std::cout << "prev=" << prev->first << '\n';
else
std::cout << "low=" << low->first << '\n';
}
"best performance possible" - given you insert elements in increasing order, you can push_back/emplace_back them into a std::vector then use std::lower_bound - you'll get better cache utilisation because the data will be packed into contiguous address space.
You could of course use lower_bound and upper_bound, which are logarithmic in runtime. And they should do what you want.
std::map<double,double>::iterator close_low;
//... your_map ...
close_low=your_map.lower_bound (current_length);
This should give you an iterator to the the first map element whose key is < current length. Do likewise with upper_bound and you have your time surrounded.
The functions std::lower_bound() and std::upper_bound() would be useful here.
lower_bound() gives the first element that is >= to the value you're looking for; upper_bound() gives the first element that is > than the value.
For instance, searching for the value 5 in the following list: {1,3,5,5,6}1 using lower_bound() returns the third element, while upper_bound() would return the fifth element.
If the two functions return the same thing x, then the value you're looking for is not present in the list.
The value just before it is x-1 and the value just after it is x.
1As pointed out by Tony D in a comment, the question asked for maps, which generally do not contain duplicate elements.
I'm keeping this example though to illustrate the two functions.
Complete generic solution (original idea taken from Olaf Dietsche's answer):
#include <map>
#include <iostream>
#include <cstdint>
template <typename T1, typename T2>
T1 findClosestKey(const std::map<T1, T2> & data, T1 key)
{
if (data.size() == 0) {
throw std::out_of_range("Received empty map.");
}
auto lower = data.lower_bound(key);
if (lower == data.end()) // If none found, return the last one.
return std::prev(lower)->first;
if (lower == data.begin())
return lower->first;
// Check which one is closest.
auto previous = std::prev(lower);
if ((key - previous->first) < (lower->first - key))
return previous->first;
return lower->first;
}
int main () {
double key = 3.3;
std::map<double, int> data = {{-10, 1000}, {0, 2000}, {10, 3000}};
std::cout << "Provided key: " << key << ", closest key: " << findClosestKey(data, key) << std::endl;
return 0;
}
#include <map>
template <typename T1, typename T2>
std::map<T1, T2>::iterator nearest_key(const std::map<T1, T2>& map, T1 key) {
auto lower_bound = map.lower_bound(key);
auto upper_bound = lower_bound; upper_bound++;
if (lower_bound == map.end()) return upper_bound;
if (upper_bound == map.end()) return lower_bound;
unsigned int dist_to_lower = std::abs((int)lower_bound->first - (int)key);
unsigned int dist_to_upper = std::abs((int)upper_bound->first - (int)key);
return (dist_to_upper < dist_to_lower) ? upper_bound : lower_bound;
}
above is wrong. should be like this
template
typename std::map<T1, T2>::const_iterator nearest_key(const std::map<T1, T2>& map, T1 key)
{
auto lower_bound = map.lower_bound(key);
if (lower_bound == map.end()) return --lower_bound;
auto upper_bound = lower_bound; upper_bound++;
if (upper_bound == map.end()) return lower_bound;
auto dist_to_lower = lower_bound->first - key;
auto dist_to_upper = upper_bound->first - key;
return (dist_to_upper < dist_to_lower) ? upper_bound : lower_bound;
}
I had to solve the same problem, however provided answers do not give me the correct answer. Here is a full example if someone wants
template <typename T>
class Key
{
public:
T x;
T y;
explicit Key(T x_, T y_): x(x_), y(y_){}
bool operator<( const Key<T> right) const{
if((x == right.x) && (y == right.y)){
return false;
}
return true;
}
T operator-( const Key<T> right) const{
return std::sqrt(std::pow(x-right.x, 2) + std::pow(y-right.y, 2));
}
};
int main(int argc, char **argv)
{
std::map<Key<double>, double> pixel_mapper;
Key<double> k1(400,5);
Key<double> k2(4,5);
Key<double> k3(4,5);
Key<double> k4(4667,5);
Key<double> k5(1000,5);
pixel_mapper.insert(std::pair<Key<double>, double>(k2, 5));
pixel_mapper.insert(std::pair<Key<double>, double>(k3, 5));
pixel_mapper.insert(std::pair<Key<double>, double>(k4, 5));
pixel_mapper.insert(std::pair<Key<double>, double>(k1, 5));
auto it = std::min_element( pixel_mapper.begin(), pixel_mapper.end(),
[&](const auto &p1, const auto &p2)
{
return std::abs(p1.first - k5) < std::abs(p2.first - k5);
});
std::cout<< it->first.x << "," << it->first.y << std::endl;
return 0;
}
Here, we can use std:min_element to get the closest in case exact key is not present
Related
What's the most widely used existing library in C++ to give all the combination and permutation of k elements out of n elements?
I am not asking the algorithm but the existing library or methods.
Thanks.
I decided to test the solutions by dman and Charles Bailey here. I'll call them solutions A and B respectively. My test is visiting each combination of of a vector<int> size = 100, 5 at a time. Here's the test code:
Test Code
struct F
{
unsigned long long count_;
F() : count_(0) {}
bool operator()(std::vector<int>::iterator, std::vector<int>::iterator)
{++count_; return false;}
};
int main()
{
typedef std::chrono::high_resolution_clock Clock;
typedef std::chrono::duration<double> sec;
typedef std::chrono::duration<double, std::nano> ns;
int n = 100;
std::vector<int> v(n);
std::iota(v.begin(), v.end(), 0);
std::vector<int>::iterator r = v.begin() + 5;
F f;
Clock::time_point t0 = Clock::now();
do
{
f(v.begin(), r);
} while (next_combination(v.begin(), r, v.end()));
Clock::time_point t1 = Clock::now();
sec s0 = t1 - t0;
ns pvt0 = s0 / f.count_;
std::cout << "N = " << v.size() << ", r = " << r-v.begin()
<< ", visits = " << f.count_ << '\n'
<< "\tnext_combination total = " << s0.count() << " seconds\n"
<< "\tnext_combination per visit = " << pvt0.count() << " ns";
}
All code was compiled using clang++ -O3 on a 2.8 GHz Intel Core i5.
Solution A
Solution A results in an infinite loop. Even when I make n very small, this program never completes. Subsequently downvoted for this reason.
Solution B
This is an edit. Solution B changed in the course of writing this answer. At first it gave incorrect answers and due to very prompt updating it now gives correct answers. It prints out:
N = 100, r = 5, visits = 75287520
next_combination total = 4519.84 seconds
next_combination per visit = 60034.3 ns
Solution C
Next I tried the solution from N2639 which looks very similar to solution A, but works correctly. I'll call this solution C and it prints out:
N = 100, r = 5, visits = 75287520
next_combination total = 6.42602 seconds
next_combination per visit = 85.3531 ns
Solution C is 703 times faster than solution B.
Solution D
Finally there is a solution D found here. This solution has a different signature / style and is called for_each_combination, and is used much like std::for_each. The driver code above changes between the timer calls like so:
Clock::time_point t0 = Clock::now();
f = for_each_combination(v.begin(), r, v.end(), f);
Clock::time_point t1 = Clock::now();
Solution D prints out:
N = 100, r = 5, visits = 75287520
for_each_combination = 0.498979 seconds
for_each_combination per visit = 6.62765 ns
Solution D is 12.9 times faster than solution C, and over 9000 times faster than solution B.
I consider this a relatively small problem: only 75 million visits. As the number of visits increases into the billions, the discrepancy in the performance between these algorithms continues to grow. Solution B is already unwieldy. Solution C eventually becomes unwieldy. Solution D is the highest performing algorithm to visit all combinations I'm aware of.
The link showing solution D also contains several other algorithms for enumerating and visiting permutations with various properties (circular, reversible, etc.). Each of these algorithms was designed with performance as one of the goals. And note that none of these algorithms requires the initial sequence to be in sorted order. The elements need not even be LessThanComparable.
Combinations: from Mark Nelson's article on the same topic we have next_combination Permutations: From STL we have std::next_permutation
template <typename Iterator>
inline bool next_combination(const Iterator first, Iterator k, const Iterator last)
{
if ((first == last) || (first == k) || (last == k))
return false;
Iterator itr1 = first;
Iterator itr2 = last;
++itr1;
if (last == itr1)
return false;
itr1 = last;
--itr1;
itr1 = k;
--itr2;
while (first != itr1)
{
if (*--itr1 < *itr2)
{
Iterator j = k;
while (!(*itr1 < *j)) ++j;
std::iter_swap(itr1,j);
++itr1;
++j;
itr2 = k;
std::rotate(itr1,j,last);
while (last != j)
{
++j;
++itr2;
}
std::rotate(k,itr2,last);
return true;
}
}
std::rotate(first,k,last);
return false;
}
This answer provides a minimal implementation effort solution. It may not have acceptable performance if you want to retrieve combinations for large input ranges.
The standard library has std::next_permutation and you can trivially build a next_k_permutation from it and a next_combination from that.
template<class RandIt, class Compare>
bool next_k_permutation(RandIt first, RandIt mid, RandIt last, Compare comp)
{
std::sort(mid, last, std::tr1::bind(comp, std::tr1::placeholders::_2
, std::tr1::placeholders::_1));
return std::next_permutation(first, last, comp);
}
If you don't have tr1::bind or boost::bind you would need to build a function object that swaps the arguments to a given comparison. Of course, if you're only interested in a std::less variant of next_combination then you can use std::greater directly:
template<class RandIt>
bool next_k_permutation(RandIt first, RandIt mid, RandIt last)
{
typedef typename std::iterator_traits<RandIt>::value_type value_type;
std::sort(mid, last, std::greater< value_type >());
return std::next_permutation(first, last);
}
This is a relatively safe version of next_combination. If you can guarantee that the range [mid, last) is in order as they would be after a call to next_combination then you can use the simpler:
template<class BiDiIt, class Compare>
bool next_k_permutation(BiDiIt first, BiDiIt mid, BiDiIt last, Compare comp)
{
std::reverse(mid, last);
return std::next_permutation(first, last, comp);
}
This also works with bi-directional iterators as well as random access iterators.
To output combinations instead of k-permutations, we have to ensure that we output each combination only once, so we'll return a combination it only if it is a k-permutation in order.
template<class BiDiIt, class Compare>
bool next_combination(BiDiIt first, BiDiIt mid, BiDiIt last, Compare comp)
{
bool result;
do
{
result = next_k_permutation(first, mid, last, comp);
} while (std::adjacent_find( first, mid,
std::tr1::bind(comp, std::tr1::placeholders::_2
, std::tr1::placeholders::_1) )
!= mid );
return result;
}
Alternatives would be to use a reverse iterator instead of the parameter swapping bind call or to use std::greater explicitly if std::less is the comparison being used.
# Charles Bailey above:
I could be wrong, but I think the first two algorithms above does not remove duplicates between first and mid? Maybe I am not sure how to use it.
4 choose 2 example:
12 34
12 43 (after sort)
13 24 (after next_permutation)
13 42 (after sort)
14 23 (after next_permutation)
14 32 (after sort)
21 34 (after next_permutation)
So I added a check to see if the value in italics is in order before returning, but definitely wouldn't have thought of the part you wrote though (very elegant! thanks!).
Not fully tested, just cursory tests..
template
bool next_combination(RandIt first, RandIt mid, RandIt last)
{
typedef typename std::iterator_traits< RandIt >::value_type value_type;
std::sort(mid, last, std::greater< value_type >() );
while(std::next_permutation(first, last)){
if(std::adjacent_find(first, mid, std::greater< value_type >() ) == mid){
return true;
}
std::sort(mid, last, std::greater< value_type >() );
return false;
}
Maybe it's already stated within the previous answers, but here I cannot find a full generic way for this with respect to the parameter types and I also didn't find it within existing library routines besides Boost. This is a generic way I needed during test case construction for scenarios with a wide spread of various parameter variations. Maybe it's helpful to you too, at least for similar scenarios. (Usable for permutation and combination with minor changes in doubt)
#include <vector>
#include <memory>
class SingleParameterToVaryBase
{
public:
virtual bool varyNext() = 0;
virtual void reset() = 0;
};
template <typename _DataType, typename _ParamVariationContType>
class SingleParameterToVary : public SingleParameterToVaryBase
{
public:
SingleParameterToVary(
_DataType& param,
const _ParamVariationContType& valuesToVary) :
mParameter(param)
, mVariations(valuesToVary)
{
if (mVariations.empty())
throw std::logic_error("Empty variation container for parameter");
reset();
}
// Step to next parameter value, return false if end of value vector is reached
virtual bool varyNext() override
{
++mCurrentIt;
const bool finished = mCurrentIt == mVariations.cend();
if (finished)
{
return false;
}
else
{
mParameter = *mCurrentIt;
return true;
}
}
virtual void reset() override
{
mCurrentIt = mVariations.cbegin();
mParameter = *mCurrentIt;
}
private:
typedef typename _ParamVariationContType::const_iterator ConstIteratorType;
// Iterator to the actual values this parameter can yield
ConstIteratorType mCurrentIt;
_ParamVariationContType mVariations;
// Reference to the parameter itself
_DataType& mParameter;
};
class GenericParameterVariator
{
public:
GenericParameterVariator() : mFinished(false)
{
reset();
}
template <typename _ParameterType, typename _ParameterVariationsType>
void registerParameterToVary(
_ParameterType& param,
const _ParameterVariationsType& paramVariations)
{
mParametersToVary.push_back(
std::make_unique<SingleParameterToVary<_ParameterType, _ParameterVariationsType>>(
param, paramVariations));
}
const bool isFinished() const { return mFinished; }
void reset()
{
mFinished = false;
mNumTotalCombinationsVisited = 0;
for (const auto& upParameter : mParametersToVary)
upParameter->reset();
}
// Step into next state if possible
bool createNextParameterPermutation()
{
if (mFinished || mParametersToVary.empty())
return false;
auto itPToVary = mParametersToVary.begin();
while (itPToVary != mParametersToVary.end())
{
const auto& upParameter = *itPToVary;
// If we are the very first configuration at all, do not vary.
const bool variedSomething = mNumTotalCombinationsVisited == 0 ? true : upParameter->varyNext();
++mNumTotalCombinationsVisited;
if (!variedSomething)
{
// If we were not able to vary the last parameter in our list, we are finished.
if (std::next(itPToVary) == mParametersToVary.end())
{
mFinished = true;
return false;
}
++itPToVary;
continue;
}
else
{
if (itPToVary != mParametersToVary.begin())
{
// Reset all parameters before this one
auto itBackwd = itPToVary;
do
{
--itBackwd;
(*itBackwd)->reset();
} while (itBackwd != mParametersToVary.begin());
}
return true;
}
}
return true;
}
private:
// Linearized parameter set
std::vector<std::unique_ptr<SingleParameterToVaryBase>> mParametersToVary;
bool mFinished;
size_t mNumTotalCombinationsVisited;
};
Possible usage:
GenericParameterVariator paramVariator;
size_t param1;
int param2;
char param3;
paramVariator.registerParameterToVary(param1, std::vector<size_t>{ 1, 2 });
paramVariator.registerParameterToVary(param2, std::vector<int>{ -1, -2 });
paramVariator.registerParameterToVary(param3, std::vector<char>{ 'a', 'b' });
std::vector<std::tuple<size_t, int, char>> visitedCombinations;
while (paramVariator.createNextParameterPermutation())
visitedCombinations.push_back(std::make_tuple(param1, param2, param3));
Generates:
(1, -1, 'a')
(2, -1, 'a')
(1, -2, 'a')
(2, -2, 'a')
(1, -1, 'b')
(2, -1, 'b')
(1, -2, 'b')
(2, -2, 'b')
For sure, this can be further optimized/specialized. For instance you can simply add a hashing scheme and/or an avoid functor if you want to avoid effective repetitions. Also, since the parameters are held as references, one might consider to protect the generator from possible error-prone usage via deleting copy/assignement constructors and operators.
Time complexity is within the theoretical permutation complexity range.
I have a set of ranges :
Range1 ---- (0-10)
Range2 ---- (15-25)
Range3 ---- (100-1000) and likewise.
I would like to have only the bounds stored since storing large ranges , it would be efficient.
Now I need to search for a number , say 14 . In this case, 14 is not present in any of the ranges whereas (say a number) 16 is present in one of the ranges.
I would need a function
bool search(ranges, searchvalue)
{
if searchvalues present in any of the ranges
return true;
else
return false;
}
How best can this be done ? This is strictly non-overlapping and the important criteria is that the search has to be most efficient.
One possibility is to represent ranges as a pair of values and define a suitable comparison function. The following should consider one range less than another if its bounds are smaller and there is no overlap. As a side effect, this comparison function doesn't let you store overlapping ranges in the set.
To look up an integer n, it can be treated as a range [n, n]
#include <set>
#include <iostream>
typedef std::pair<int, int> Range;
struct RangeCompare
{
//overlapping ranges are considered equivalent
bool operator()(const Range& lhv, const Range& rhv) const
{
return lhv.second < rhv.first;
}
};
bool in_range(const std::set<Range, RangeCompare>& ranges, int value)
{
return ranges.find(Range(value, value)) != ranges.end();
}
int main()
{
std::set<Range, RangeCompare> ranges;
ranges.insert(Range(0, 10));
ranges.insert(Range(15, 25));
ranges.insert(Range(100, 1000));
std::cout << in_range(ranges, 14) << ' ' << in_range(ranges, 16) << '\n';
}
The standard way to handle this is through so called interval trees. Basically, you augment an ordinary red-black tree with additional information so that each node x contains an interval x.int and the key of x is the low endpoint, x.int.low, of the interval. Each node x also contains a value x.max, which is the maximum value of any interval endpoint stored in the subtree rooted at x. Now you can determine x.max given interval x.int and the max values of node x’s children as follows:
x.max = max(x.int.high, x.left.max, x.right.max)
This implies that, with n intervals, insertion and deletion run in O(lg n) time. In fact, it is possible to update the max attributes after a rotation in O(1) time. Here is how to search for an element i in the interval tree T
INTERVAL-SEARCH(T, i)
x = T:root
while x is different from T.nil and i does not overlap x.int
if x.left is different from T.nil and x.left.max is greater than or equal to i.low
x = x.left
else
x = x.right
return x
The complexity of the search procedure is O(lg n) as well.
To see why, see CLRS Introduction to algorithms, chapter 14 (Augmenting Data Structures).
You could put something together based on std::map and std::map::upper_bound:
Assuming you have
std::map<int,int> ranges; // key is start of range, value is end of range
You could do the following:
bool search(const std::map<int,int>& ranges, int searchvalue)
{
auto p = ranges.upper_bound(searchvalue);
// p->first > searchvalue
if(p == ranges.begin())
return false;
--p; // p->first <= searchvalue
return searchvalue >= p->first && searchvalue <= p->second;
}
I'm using C++11, if you use C++03, you'll need to replace "auto" by the proper iterator type.
EDIT: replaced pseudo-code inrange() by explicit expression in return statement.
A good solution can be as the following. It is O(log(n)).
A critical condition is non overlapping ranges.
#include <set>
#include <iostream>
#include <assert.h>
template <typename T> struct z_range
{
T s , e ;
z_range ( T const & s,T const & e ) : s(s<=e?s:e), e(s<=e?e:s)
{
}
};
template <typename T> bool operator < (z_range<T> const & x , z_range<T> const & y )
{
if ( x.e<y.s)
return true ;
return false ;
}
int main(int , char *[])
{
std::set<z_range<int> > x;
x.insert(z_range<int>(20,10));
x.insert(z_range<int>(30,40));
x.insert(z_range<int>(5,9));
x.insert(z_range<int>(45,55));
if (x.find(z_range<int>(15,15)) != x.end() )
std::cout << "I have it" << std::endl ;
else
std::cout << "not exists" << std::endl ;
}
If you have ranges ri = [ai, bi]. You could sort all the ai and put them into an array and search for x having x >= ai and ai minimal using binary search.
After you found this element you have to check whether x <= bi.
This is suitable if you have big numbers. If, on the other hand, you have either a lot of memory or small numbers, you can think about putting those ranges into a bool array. This may be suitable if you have a lot of queries:
bool ar[];
ar[0..10] = true;
ar[15..25] = true;
// ...
bool check(int searchValues) {
return ar[searchValues];
}
Since the ranges are non-overlapping the only thing left to do is performing a search within the range that fit's the value. If the values are ordered within the ranges, searching is even simpler. Here is a summary of search algorithms.
With respect to C++ you also can use algorithms from STL or even functions provided by the containers, e. g. set::find.
So, this assumes the ranges are continous (i.e range [100,1000] contains all numbers between 100 and 1000):
#include <iostream>
#include <map>
#include <algorithm>
bool is_in_ranges(std::map<int, int> ranges, int value)
{
return
std::find_if(ranges.begin(), ranges.end(),
[&](std::pair<int,int> pair)
{
return value >= pair.first && value <= pair.second;
}
) != ranges.end();
}
int main()
{
std::map<int, int> ranges;
ranges[0] = 10;
ranges[15] = 25;
ranges[100] = 1000;
std::cout << is_in_ranges(ranges, 14) << '\n'; // 0
std::cout << is_in_ranges(ranges, 16) << '\n'; // 1
}
In C++03, you'd need a functor instead of a lambda function:
struct is_in {
is_in(int x) : value(x) {}
bool operator()(std::pair<int, int> pair)
{
return value >= pair.first && value <= pair.second;
}
private:
int value;
};
bool is_in_ranges(std::map<int, int> ranges, int value)
{
return
std::find_if(ranges.begin(), ranges.end(), is_in(value)) != ranges.end();
}
I need a function that takes a vector (assumed to be sorted), and a value, and returns the closest number that's [edit] greater than less than or equal to that number, preferably using an algorithm from the STL. I have come up with a solution using std::lower_bound(), but it seems kludgy and ugly:
struct ClosestCmp {
bool operator()(const int & x, const int & y) { return x > y; }
};
// vec is assumed to be sorted
int closest(const std::vector<int> & vec, int value)
{
std::vector<int>::const_reverse_iterator cri =
std::lower_bound(vec.rbegin(), vec.rend(), value, ClosestCmp());
if (cri != vec.rend()) {
return *cri;
}
return -1;
}
// ...
vec.push_back(1);
vec.push_back(2);
vec.push_back(4);
vec.push_back(5);
std::cout << closest(vec, 2) << "\n"; // Should ouput "2"
std::cout << closest(vec, 3) << "\n"; // Should ouput "2"
std::cout << closest(vec, 4) << "\n"; // Should ouput "4"
Can anyone suggest a way that's more elegant, maybe using an STL algorithm without needing a comparison function or a reverse iterator? I have looked in the STL, but haven't been able to find a better solution than this.
For reminder:
std::lower_bound: returns the first value that does not compare less
std::upper_bound: returns the first value that compares strictly greater
From your description, std::lower_bound already looks like the perfect fit, what is wrong with:
int closest(std::vector<int> const& vec, int value) {
auto const it = std::lower_bound(vec.begin(), vec.end(), value);
if (it == vec.end()) { return -1; }
return *it;
}
Which is used as:
int main() {
std::vector<int> vec;
vec.push_back(2);
vec.push_back(4);
std::cout << closest(vec, 2) << "\n";
std::cout << closest(vec, 3) << "\n";
std::cout << closest(vec, 4) << "\n";
}
Output:
2
4
4
Requires C++11:
template<typename InputIterator, typename ValueType>
InputIterator closest(InputIterator first, InputIterator last, ValueType value)
{
return std::min_element(first, last, [&](ValueType x, ValueType y)
{
return std::abs(x - value) < std::abs(y - value);
});
}
You can only use std::lower_bound and std::upper_bound with binary predicates that match the order of the container. So, you can't sort by < and then use a different binary predicate (say <= or >). So your "kludge" is actually the correct thing to do. The sorted vector in reverse is the ordering criteria you want to use to find the element less than or equal to the value. (Otherwise, if you were actually searching for the value greater than or equal to, you could just use std::lower_bound.)
For the largest which is less or equal one can use this function
int closest(std::vector<int> const& vec, int value) {
auto const it = std::lower_bound(vec.begin(), vec.end(), value);
if (it == vec.begin()) { return -1; }
else return *(it - 1);
}
I'm trying to check if a given key is in a map and somewhat can't do it:
typedef map<string,string>::iterator mi;
map<string, string> m;
m.insert(make_pair("f","++--"));
pair<mi,mi> p = m.equal_range("f");//I'm not sure if equal_range does what I want
cout << p.first;//I'm getting error here
so how can I print what is in p?
Use map::find and map::end:
if (m.find("f") == m.end()) {
// not found
} else {
// found
}
To check if a particular key in the map exists, use the count member function in one of the following ways:
m.count(key) > 0
m.count(key) == 1
m.count(key) != 0
The documentation for map::find says: "Another member function, map::count, can be used to just check whether a particular key exists."
The documentation for map::count says: "Because all elements in a map container are unique, the function can only return 1 (if the element is found) or zero (otherwise)."
To retrieve a value from the map via a key that you know to exist, use map::at:
value = m.at(key)
Unlike map::operator[], map::at will not create a new key in the map if the specified key does not exist.
C++20 gives us std::map::contains to do that.
#include <iostream>
#include <string>
#include <map>
int main()
{
std::map<int, std::string> example = {{1, "One"}, {2, "Two"},
{3, "Three"}, {42, "Don\'t Panic!!!"}};
if(example.contains(42)) {
std::cout << "Found\n";
} else {
std::cout << "Not found\n";
}
}
You can use .find():
map<string,string>::iterator i = m.find("f");
if (i == m.end()) { /* Not found */ }
else { /* Found, i->first is f, i->second is ++-- */ }
C++17 simplified this a bit more with an If statement with initializer.
This way you can have your cake and eat it too.
if ( auto it{ m.find( "key" ) }; it != std::end( m ) )
{
// Use `structured binding` to get the key
// and value.
const auto&[ key, value ] { *it };
// Grab either the key or value stored in the pair.
// The key is stored in the 'first' variable and
// the 'value' is stored in the second.
const auto& mkey{ it->first };
const auto& mvalue{ it->second };
// That or just grab the entire pair pointed
// to by the iterator.
const auto& pair{ *it };
}
else
{
// Key was not found..
}
m.find == m.end() // not found
If you want to use other API, then find go for m.count(c)>0
if (m.count("f")>0)
cout << " is an element of m.\n";
else
cout << " is not an element of m.\n";
I think you want map::find. If m.find("f") is equal to m.end(), then the key was not found. Otherwise, find returns an iterator pointing at the element found.
The error is because p.first is an iterator, which doesn't work for stream insertion. Change your last line to cout << (p.first)->first;. p is a pair of iterators, p.first is an iterator, p.first->first is the key string.
A map can only ever have one element for a given key, so equal_range isn't very useful. It's defined for map, because it's defined for all associative containers, but it's a lot more interesting for multimap.
template <typename T, typename Key>
bool key_exists(const T& container, const Key& key)
{
return (container.find(key) != std::end(container));
}
Of course if you wanted to get fancier you could always template out a function that also took a found function and a not found function, something like this:
template <typename T, typename Key, typename FoundFunction, typename NotFoundFunction>
void find_and_execute(const T& container, const Key& key, FoundFunction found_function, NotFoundFunction not_found_function)
{
auto& it = container.find(key);
if (it != std::end(container))
{
found_function(key, it->second);
}
else
{
not_found_function(key);
}
}
And use it like this:
std::map<int, int> some_map;
find_and_execute(some_map, 1,
[](int key, int value){ std::cout << "key " << key << " found, value: " << value << std::endl; },
[](int key){ std::cout << "key " << key << " not found" << std::endl; });
The downside to this is coming up with a good name, "find_and_execute" is awkward and I can't come up with anything better off the top of my head...
map<string, string> m;
check key exist or not, and return number of occurs(0/1 in map):
int num = m.count("f");
if (num>0) {
//found
} else {
// not found
}
check key exist or not, and return iterator:
map<string,string>::iterator mi = m.find("f");
if(mi != m.end()) {
//found
//do something to mi.
} else {
// not found
}
in your question, the error caused by bad operator<< overload, because p.first is map<string, string>, you can not print it out. try this:
if(p.first != p.second) {
cout << p.first->first << " " << p.first->second << endl;
}
Be careful in comparing the find result with the the end like for map 'm' as all answer have
done above
map::iterator i = m.find("f");
if (i == m.end())
{
}
else
{
}
you should not try and perform any operation such as printing the key or value with iterator i if its equal to m.end() else it will lead to segmentation fault.
Comparing the code of std::map::find and std::map::count, I'd say the first may yield some performance advantage:
const_iterator find(const key_type& _Keyval) const
{ // find an element in nonmutable sequence that matches _Keyval
const_iterator _Where = lower_bound(_Keyval); // Here one looks only for lower bound
return (_Where == end()
|| _DEBUG_LT_PRED(this->_Getcomp(),
_Keyval, this->_Key(_Where._Mynode()))
? end() : _Where);
}
size_type count(const key_type& _Keyval) const
{ // count all elements that match _Keyval
_Paircc _Ans = equal_range(_Keyval); // Here both lower and upper bounds are to be found, which is presumably slower.
size_type _Num = 0;
_Distance(_Ans.first, _Ans.second, _Num);
return (_Num);
}
I know this question already has some good answers but I think my solution is worth of sharing.
It works for both std::map and std::vector<std::pair<T, U>> and is available from C++11.
template <typename ForwardIterator, typename Key>
bool contains_key(ForwardIterator first, ForwardIterator last, Key const key) {
using ValueType = typename std::iterator_traits<ForwardIterator>::value_type;
auto search_result = std::find_if(
first, last,
[&key](ValueType const& item) {
return item.first == key;
}
);
if (search_result == last) {
return false;
} else {
return true;
}
}
map <int , char>::iterator itr;
for(itr = MyMap.begin() ; itr!= MyMap.end() ; itr++)
{
if (itr->second == 'c')
{
cout<<itr->first<<endl;
}
}
If you want to compare pair of map you can use this method:
typedef map<double, double> TestMap;
TestMap testMap;
pair<map<double,double>::iterator,bool> controlMapValues;
controlMapValues= testMap.insert(std::pair<double,double>(x,y));
if (controlMapValues.second == false )
{
TestMap::iterator it;
it = testMap.find(x);
if (it->second == y)
{
cout<<"Given value is already exist in Map"<<endl;
}
}
This is a useful technique.
Given a sorted vector with a number of values, as in the following example:
std::vector<double> f;
f.pushback(10);
f.pushback(100);
f.pushback(1000);
f.pushback(10000);
I'm looking for the most elegant way to retrieve for any double d the two values that are immediately adjacent to it. For example, given the value "45", I'd like this to return "10" and "100".
I was looking at lower_bound and upper_bound, but they don't do what I want. Can you help?
EDIT: I've decided to post my own anser, as it is somewhat a composite of all the helpful answers that I got in this thread. I've voted up those answers which I thought were most helpful.
Thanks everyone,
Dave
You can grab both values (if they exist) in one call with equal_range(). It returns a std::pair of iterators, with first being the first location and second being the last location in which you could insert the value passed without violating ordering. To strictly meet your criteria, you'd have to decrement the iterator in first, after verifying that it wasn't equal to the vector's begin().
You can use STL's lower_bound to get want you want in a few lines of code. lower_bound uses binary search under the hood, so your runtime is O(log n).
double val = 45;
double lower, upper;
std::vector<double>::iterator it;
it = lower_bound(f.begin(), f.end(), val);
if (it == f.begin()) upper = *it; // no smaller value than val in vector
else if (it == f.end()) lower = *(it-1); // no bigger value than val in vector
else {
lower = *(it-1);
upper = *it;
}
You could simply use a binary search, which will run in O(log(n)).
Here is a Lua snippet (I don't have time to do it in C++, sorry) which does what you want, except for limit conditions (that you did not define anyway) :
function search(value, list, first, last)
if not first then first = 1; last = #list end
if last - first < 2 then
return list[first], list[last]
end
local median = math.ceil(first + (last - first)/2)
if list[median] > value then
return search(value, list, first, median)
else
return search(value, list, median, last)
end
end
local list = {1,10,100,1000}
print(search(arg[1] + 0, list))
It takes the value to search from the command line :
$ lua search.lua 10 # didn't know what to do in this case
10 100
$ lua search.lua 101
100 1000
$ lua search.lua 99
10 100
I'm going to post my own anser, and vote anyone up that helped me to reach it, since this is what I'll use in the end, and you've all helped me reach this conclusion. Comments are welcome.
std::pair<value_type, value_type> GetDivisions(const value_type& from) const
{
if (m_divisions.empty())
throw 0; // Can't help you if we're empty.
std::vector<value_type>::const_iterator it =
std::lower_bound(m_divisions.begin(), m_divisions.end(), from);
if (it == m_divisions.end())
return std::make_pair(m_divisions.back(), m_divisions.back());
else if (it == m_divisions.begin())
return std::make_pair(m_divisions.front(), m_divisions.front());
else
return std::make_pair(*(it - 1), *(it));
}
What if (in your case) d is less than the first element or more than the last? And how to deal with negative values? By the way: guaranteeing that your "d" lives between the first and the last value of your vector you can do like that:
// Your initializations
std::vector<double>::const_iterator sit = f.begin();
double upper, lower;
Here is the rest:
while ( *sit < d ) // if the element is still less than your d
++sit; // increase your iterator
upper = *sit; // here you get the upper value
lower = *(--sit); // and here your lower
Elegant enough? :/
You could do a search in your vector for your value (which would tell you where your value would be if it were in the vector) and then return the value before and after that location. So searching for 45 would tell you it should be at index=1 and then you would return 0 and 1 (depending on your implementation of the search, you'll either get the index of the smaller value or the index of the larger value, but this is easy to check with a couple boundary conditions). This should be able to run in O(log n) where n is the number of elements in your vector.
I would write something like this, didn't test if this compiles, but you get the idea:
template <typename Iterator>
std::pair<Iterator, Iterator> find_best_pair(Iterator first, Iterator last, const typename Iterator::value_type & val)
{
std::pair<Iterator, Iterator> result(last, last);
typename Iterator::difference_type size = std::distance(first, last);
if (size == 2)
{
// if the container is of size 2, the answer is the two elements
result.first = first;
result.first = first;
++result.first;
}
else
{
// must be of at lease size 3
if (size > 2)
{
Iterator second = first;
++second;
Iterator prev_last = last;
--prev_last;
Iterator it(std::lower_bound(second, last, val));
if (it != last)
{
result.first = it;
result.second = it;
if (it != prev_last)
{
// if this is not the previous last
// then the answer is (it, it + 1)
++result.second;
}
else
{
// if this the previous last
// then the answer is (it - 1, it)
--result.first;
}
}
}
}
return result;
}
I wrote up this little function, which seems to fit the more general case you wanted. I haven't tested it totally, but I did write a little test code (included).
#include <algorithm>
#include <iostream>
#include <vector>
template <class RandomAccessIt, class Container, class T>
std::pair<RandomAccessIt, RandomAccessIt> bracket_range(RandomAccessIt begin, RandomAccessIt end, Container& c, T val)
{
typename Container::iterator first;
typename Container::iterator second;
first = std::find(begin, end, val);
//Find the first value after this by iteration
second = first;
if (first == begin){ // Found the first element, so set this to end to indicate no lower values
first = end;
}
else if (first != end && first != begin) --first; //Set this to the first value before the found one, if the value was found
while (second != end && *second == val) ++second;
return std::make_pair(first,second);
}
int main(int argc, _TCHAR* argv[])
{
std::vector<int> values;
std::pair<std::vector<int>::iterator, std::vector<int>::iterator> vals;
for (int i = 1; i < 9; ++i) values.push_back(i);
for (int i = 0; i < 10; ++i){
vals = bracket_range(values.begin(), values.end(),values, i);
if (vals.first == values.end() && vals.second == values.end()){ // Not found at all
std::cout << i << " is not in the container." << std::endl;
}
else if (vals.first == values.end()){ // No value lower
std::cout << i << ": " << "None Lower," << *(vals.second) << std::endl;
}
else if (vals.second == values.end()) { // No value higher
std::cout << i << ": " << *(vals.first) << ", None Higher" << std::endl;
}
else{
std::cout << i << ": " << *(vals.first) << "," << *(vals.second) << std::endl;
}
}
return 0;
}
Based on the code that tunnuz posted, here you have some improvements regarding bound checking:
template<typename T>
void find_enclosing_values(const std::vector<T> &vec, const T &value, T &lower, T &upper, const T &invalid_value)
{
std::vector<T>::const_iterator it = vec.begin();
while (it != vec.end() && *it < value)
++it;
if(it != vec.end())
upper = *it;
else
upper = invalid_value;
if(it == vec.begin())
lower = invalid_value;
else
lower = *(--it);
}
Example of usage:
std::vector<int> v;
v.push_back(3);
v.push_back(7);
v.push_back(10);
int lower, upper;
find_enclosing_values(v, 4, lower, upper, -1);
std::cout<<"lower "<<lower<<" upper "<<upper<<std::endl;
If you have the ability to use some other data structure (not a vector), I'd suggest a B-tree. If you data is unchanging, I believe you can retrieve the result in constant time (logarithmic time at the worst).