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);
}
Related
I have a vector of pair:
typedef pair<string,int> is;
vector<is> v;
I push some values to the vector.
v.push_back(make_pair("One",1));
v.push_back(make_pair("Two",2));
v.push_back(make_pair("Three",3));
v.push_back(make_pair("Four",4));
I need to ask the user to input a name and search the vector , find that name and output it's corresponding int in the pair. If user types "One" I want the input to type 1.
I tried the following.
struct comp_pair_int
{
bool operator()(const pair<string, int>& a, const string& b)
{
return (a.first < b);
}
bool operator()(const string& a, const pair<string, int>& b)
{
return (a < b.first);
}
};
sort(v.begin(),v.end(),comparison);
if (binary_search(v.begin(), v.end(),
"One", comp_pair_int()))
cout << "Element found\n";
else
cout << "Element not found";
That code returns if the element is found or not, but that's not all I want, I also need to output the second element in the pair of the found element. How can I do that?
std::binary_search will only give you a bool result, so it doesn't give sufficient information to get the value of the pair you're looking for.
The idiomatic way to do this is with std::lower_bound, which returns an iterator to the pair you're looking for, like this:
if (auto i = std::lower_bound(v.begin(), v.end(),
"One", comp_pair_int());
i != v.end() && i->first == "One") // lower bound actually found correct pair
cout << "Element found with value " << i->second;
else
cout << "Element not found";
Note that as with binary_search the range needs to be sorted by the same predicate you use for the search.
You could use std::find_if if your vector is not sorted by key.
Would look like this:
auto it = std::find_if(v.begin(), v.end(), [&](const is& item) {
return item.first == user_input;
});
if(it != v.end()) {
int my_item = it->second;
}
else {
// key not found
}
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;
}
Problem
Suppose I have two iterators begin and end of type Iterator and some predicate predicate (stored in obj). I want to implement method some_collection() o that I can write
for(auto element: obj.get_collection()) {
do_smth()
}
so that it's work only on elements which satisfy predicate (i.e eqiuvalent to smth like this)
for (auto element: range(begin, end)) {
if (predicate(element)) {
do_smth();
}
}
My solution
Approximate implementation I have in mind is the following (pseudocode):
struct Wrapper {
op++() {
do {
++value;
while (!predicate(*value));
}
op*() {
return *value;
}
op !=(Iterator other) {
return value != other.value;
}
Iterator value;
}
Where begin() of returned object will be like
value = begin;
while (!predicate(*value)) ++value;
return Wrapper(value)
and end() is just Wrapper(end)
Caveats
What I don't like in this implementation:
Wordiness: I just need to filter, and have to write ton of code
Initialisation is kind of ugly - have to increment right there
If I won't iterate over all objects (will break or just don't use any values) I'll iterate extra (to the next unused element)
I could iterate before each dereference (to fix 2nd and 3rd points) but it will make != end check harder (either I need to decrement end in advance or use increment in check itself which means passing input range two times during the cycle)
Requirements
I don't have specific language version requirements and even interested in implementations using not yet approved. But C++11 would be the greatest
I don't have specific requirements for iterator category supported. I believe Mine will work with ForwardIterators.
I'm interested in both understandability of the code and its efficiency.
Any solution that is closer to silver bullet? :)
You could use a BOOST filter_iterator. Here is the example from the linked page:
struct is_positive_number {
bool operator()(int x) { return 0 < x; }
};
int main()
{
int numbers_[] = { 0, -1, 4, -3, 5, 8, -2 };
const int N = sizeof(numbers_)/sizeof(int);
typedef int* base_iterator;
base_iterator numbers(numbers_);
// Example using filter_iterator
typedef boost::filter_iterator<is_positive_number, base_iterator>
FilterIter;
is_positive_number predicate;
FilterIter filter_iter_first(predicate, numbers, numbers + N);
FilterIter filter_iter_last(predicate, numbers + N, numbers + N);
std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
// Example using make_filter_iterator()
std::copy(boost::make_filter_iterator<is_positive_number>(numbers, numbers + N),
boost::make_filter_iterator<is_positive_number>(numbers + N, numbers + N),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
// Another example using make_filter_iterator()
std::copy(
boost::make_filter_iterator(
std::bind2nd(std::greater<int>(), -2)
, numbers, numbers + N)
, boost::make_filter_iterator(
std::bind2nd(std::greater<int>(), -2)
, numbers + N, numbers + N)
, std::ostream_iterator<int>(std::cout, " ")
);
std::cout << std::endl;
return boost::exit_success;
}
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
I have a multimap defined by
typedef std::pair<int, int> comp_buf_pair; //pair<comp_t, dij>
typedef std::pair<int, comp_buf_pair> node_buf_pair;
typedef std::multimap<int, comp_buf_pair> buf_map; //key=PE, value = pair<comp_t, dij>
typedef buf_map::iterator It_buf;
int summ (int x, int y) {return x+y;}
int total_buf_size = 0;
std::cout << "\nUpdated buffer values" << std::endl;
for(It_buf it = bufsz_map.begin(); it!= bufsz_map.end(); ++it)
{
comp_buf_pair it1 = it->second;
// max buffer size will be summ(it1.second)
//total_buf_size = std::accumulate(bufsz_map.begin(), bufsz_map.end(), &summ); //error??
std::cout << "Total buffers required for this config = " << total_buf_size << std::endl;
std::cout << it->first << " : " << it1.first << " : " << it1.second << std::endl;
}
I would like to sum all the values pointed by it1.second
How can the std::accumulate function access the second iterator values?
Your issue is with the summ function, you actually need something better than that to be able to handle 2 mismatched types.
If you're lucky, this could work:
int summ(int x, buf_map::value_type const& v) { return x + v.second; }
If you're unlucky (depending on how accumulate is implemented), you could always:
struct Summer
{
typedef buf_map::value_type const& s_type;
int operator()(int x, s_type v) const { return x + v.second.first; }
int operator()(s_type v, int x) const { return x + v.second.first; }
};
And then use:
int result = std::accumulate(map.begin(), map.end(), 0, Summer());
I think you'll just need to change your summ function to take the map value_type instead. This is totally untested but it should give the idea.
int summ (int x, const buf_map::value_type& y)
{
return x + y.second;
}
And call it:
total_buf_size = std::accumulate(bufsz_map.begin(), bufsz_map.end(), 0, &summ);
Why do you mess about with pairs containing pairs? It is too complicated and you'll wind up making errors. Why not define a struct?
Accumulate is a generalization of summation: it computes the sum (or some other binary operation) of init and all of the elements in the range [first, last).
... The result is first initialized to init. Then, for each iterator i in [first, last), in order from beginning to end, it is updated by result = result + *i (in the first version) or result = binary_op(result, *i) (in the second version).
Sgi.com
Your attempt was neither first or second version, you missed the init part
total_buf_size = std::accumulate(bufsz_map.begin(), bufsz_map.end(), 0, &summ);