C++ STL: std::find with std::map - c++

Python allows you to write if e in arr: ... and if key in dict: ... which is handy.
Can we do something similar with the latter using std::find() and std::map ? That will allow me to uniformly handle std::array and std::map with a single generic function, without explicitly switching to std::map::find().
But if overloading operator==() is the only way, I'd rather give up this idea...
Update: note I already have a sort of solution
By "overloading operator==()" I meant something like this:
template<typename K>
struct KF {
K&& k;
template <typename V>
friend bool operator==(const typename std::pair<const K, V>& pair, const KF<K>& o) {
return pair.first == o.k;
}
};
template <typename K>
KF<K> keyFinder(K&& k) { return KF<K>{ std::forward<K>(k) }; }
int main() {
std::set<int> s{ 1, 2, };
cout << (std::find(s.begin(), s.end(), 1) == s.end()) << endl; // => 0
cout << (std::find(s.begin(), s.end(), 3) == s.end()) << endl; // => 1
std::map<int, int> m{ {1,10}, {2,20}, };
cout << (std::find(m.begin(), m.end(), keyFinder(1)) == m.end()) << endl; // => 0
cout << (std::find(m.begin(), m.end(), keyFinder(3)) == m.end()) << endl; // => 1
}
http://ideone.com/7ULUe9
Things get more complicated when we deal with non-scalar K in an universal way (perfect forwarding etc. ?)

...why not write your own utility function?
template <typename TContainer, typename TValue>
bool contains(const TContainer& c, const TValue& x);
You can use overloading to match the containers:
template <typename TValue, std::size_t N>
bool contains(const std::array<TValue, N>& c, const TValue& x)
{
return std::find(std::begin(c), std::end(c), x) != std::end(c);
}
template <typename TValue, typename... Ts>
bool contains(const std::map<Ts...>& c, const TValue& x)
{
return c.find(x) != std::end(c);
}
Usage:
std::array<int, 2> a{1,2};
std::map<int, int> b{{1,2},{3,4}};
assert(contains(a, 1));
assert(!contains(a, 42));
assert(contains(b, 1));
assert(!contains(b, 42));
live example on wandbox
If you want to support additional containers in the future, it's a good idea to use SFINAE to check whether or not a particular expression is valid. This approach works well because it doesn't care about the type of the container, it only cares about what operations can be performed on it.
The detection idiom would likely make it very easy to check member availability through SFINAE (and its implementation is C++11 compatible).
I also wrote an article about checking expression validity in-situ with C++17, which could be an interesting read. Despite its title, it covers C++11, C++14 and C++17 techniques to check expression validity:
"checking expression validity in-place with C++17"

To answer your explicit question - no, std::find won't be able to work uniformly for std::map/std::unordered_map and std::array/std::vector as the former is a collection of key/value pairs and the latter is collection of values...
You may want to use std::find_if instead as it gives you a little bit more flexibility on defining equality condition e.g. like this (c++1z approach):
#include <array>
#include <map>
#include <string>
#include <algorithm>
#include <type_traits>
template <class T>
struct is_pair: std::false_type { };
template <class K, class V>
struct is_pair<std::pair<K,V>>: std::true_type { };
int main() {
std::map<std::string, int> m {{"abc", 1}, {"cde", 2}, {"efg", 3}};
std::array<int, 5> a{1, 2, 3, 4, 5};
auto lambda = [](auto it) {
if constexpr (is_pair<decltype(it)>::value) {
return it.second == 3;
} else {
return it == 3;
}
};
assert(std::find_if(a.begin(), a.end(), lambda) != a.end());
assert(std::find_if(m.begin(), m.end(), lambda) != m.end());
}
[live demo]
Have in mind that this approach won't work as expected if you decide to search through collection like std::vector<std::pair<int, int>>.

Related

Function to find duplicate values after applying a function

I'd like a function in C++ which finds an item in a collection which has the same value of function(key) as another item in the collection.
e.g.
std::set<int> ints = {1, -1, 3};
// Finds an item in the set with the same absolute value as
// another item.
int* dupe = find_duplicates(ints, [](int x) { return std::abs(x); });
// Should print -1 or 1
if (dupe != 0) std::cout << "Found dupe: " << *dupe << std::endl;
However, I'm having trouble even writing the function signature for this method.
In Java it'd be something like static Integer findDuplicates<T, U>(Iterable<T>, Function<T, U> func).
In C++ I've got as far as the following, but it doesn't compile:
template<template <typename T> Collection, typename U>
T* find_duplicates(
const Collection<T>& collection,
const std::function<U(T)>& func) { ... }
The error I get is error: 'T' does not name a type.
Any pointers? (I'd also be interested in a way to get around the use of the "raw" pointer to T*, but that's probably better for a separate question)
In your example, T is unrecognizable and virtually useless. You should introduce the type T earlier and then use it to specify the Collection, like so:
template<typename T, template <typename> typename Collection, typename U>
T* find_duplicates(const Collection<T>& collection,
const std::function<U(T)>& func)
{
// some logic here
}
Also: notice that you missed a single typename before the Collection, as I pointed out in a comment previously. The above example is adjusted for that suggestion.
For your specific example, something like this should work,
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
int main() {
std::set<int> ints = {1, -1, 3};
auto dupe = std::find_if(ints.begin(),ints.end(),[&](const int& first){
return std::find_if(ints.begin(),ints.end(),[&](const int& second) {
// so a the same value isn't checked against itself..
if (&first == &second) return false;
return std::abs(first) == std::abs(second);
}) != ints.end();
} );
if (dupe != ints.end()) std::cout << "Found dupe: " << *dupe << std::endl;
}
Demo
Don't be so picky about your function parameter types. You don't really need collection to be a class template specialization, just something you can iterate over (which could even be a C-style array). func just needs to be invokable, and forcing it to be a std::function object can be less efficient than directly using a function pointer or lambda, because of the type erasure std::function adds and then resolves.
So a working declaration could be
template <typename Collection, typename Func>
auto find_duplicates(Collection& collection, const Func& func)
-> typename std::iterator_traits<decltype(std::begin(collection))>::value_type*;
I would do:
#include <utility>
#include <iterator>
#include <set>
// Calling with an rvalue collection would be bad news.
template <typename Collection, typename Func>
void find_duplicates(Collection&&, const Func&) = delete;
template <typename Collection, typename Func>
auto find_duplicates(Collection& collection, const Func& func)
-> typename std::iterator_traits<decltype(std::begin(collection))>::value_type*
{
auto iter = std::begin(collection);
using value_type = typename std::iterator_traits<decltype(iter)>::value_type;
auto ptr_compare = [&func](value_type* p, value_type* q)
{ return func(*p) < func(*q); };
std::set<value_type*, decltype(ptr_compare)> iter_set{ptr_compare};
for (; iter != std::end(collection); ++iter) {
auto insert_result = iter_set.insert(std::addressof(*iter));
if (!insert_result.second)
return *insert_result.first;
}
return nullptr;
}
Sometimes a raw pointer really is the answer. It implies the value might be null, and that the pointer has no ownership relation to the object. In this case, not using the pointer after it's invalidated by modifying or destroying the container is up to the caller, but it has the usual pointer-to-container-element invalidation semantics which depend on the container details.
This won't work with std::vector<bool> or any other pseudo-container where *collection.begin() has a "proxy" type. If you want to support those and can use C++17 std::optional or boost::optional, you could return an optional<value_type> instead of a raw pointer, though this will make a copy of the returned duplicated value. If you can't use those or a copy is undesirable, maybe write a template class iter_or_null<InputIter> that contains an iterator, has operator* and operator-> that just call the iterator's operators, and satisfies the NullablePointer concept.
You're actually being too restrictive with your template. You want your template to take any container for which std::begin and std::end are defined, and any function object that can accept an instance of whatever the container contains. In the template world, you just accept any type, use it the way you would like to, and if the caller doesn't provide a compatibly-typed object, they will get a compilation error.
Further, there's no need to use std::function - it will end up potentially allocating memory when you can just accept the function object as a parameter with a deduced type.
With C++14, auto-deduced return types and auto parameters to lambdas allow you to write very generic code. Here's my solution. It returns an iterator into the container pointing to the first duplicate found, or std::end(c) if no duplicate is found.
#include <algorithm>
#include <cmath>
#include <iterator>
#include <iostream>
#include <set>
template<typename C, typename F>
auto find_duplicates(const C & c, const F & func)
{
return std::find_if(std::begin(c), std::end(c), [&](const auto & first) {
return std::any_of(std::begin(c), std::end(c), [&](const auto & second) {
return &first != &second && func(first) == func(second);
});
});
}
int main()
{
std::set<int> s{1, 3, -1};
auto const iter = find_duplicates(s, [](int x) { return std::abs(x); });
if (iter != std::end(s))
{
std::cout << "Duplicate found: " << *iter << '\n';
}
}
EDIT: I just noticed you specified the C++11 tag. It's only a little more complicated in C++11:
template<typename C, typename F>
auto find_duplicates(const C & c, const F & func) -> decltype(std::begin(c))
{
using ContainedType = decltype(*std::begin(c));
return std::find_if(std::begin(c), std::end(c), [&](const ContainedType & first) {
return std::any_of(std::begin(c), std::end(c), [&](const ContainedType & second) {
return &first != &second && func(first) == func(second);
});
});
}

C++ Transform a std::tuple<A, A, A...> to a std::vector or std::deque

In the simple parser library I am writing, the results of multiple parsers is combined using std::tuple_cat. But when applying a parser that returns the same result multiple times, it becomes important to transform this tuple into a container like a vector or a deque.
How can this be done? How can any tuple of the kind std::tuple<A>, std::tuple<A, A>, std::tuple<A, A, A> etc be converted into a std::vector<A>?
I think this might be possible using typename ...As and sizeof ...(As), but I am not sure how to create a smaller tuple to call the function recursively. Or how to write an iterative solution that extracts elements from the tuple one by one. (as std::get<n>(tuple) is constructed at compile-time).
How to do this?
With the introduction of std::apply(), this is very straightforward:
template <class Tuple,
class T = std::decay_t<std::tuple_element_t<0, std::decay_t<Tuple>>>>
std::vector<T> to_vector(Tuple&& tuple)
{
return std::apply([](auto&&... elems){
return std::vector<T>{std::forward<decltype(elems)>(elems)...};
}, std::forward<Tuple>(tuple));
}
std::apply() is a C++17 function but is implementable in C++14 (see link for possible implementation). As an improvement, you could add either SFINAE or a static_assert that all the types in the Tuple are actually T.
As T.C. points out, this incurs an extra copy of every element, since std::initializer_list is backed by a const array. That's unfortunate. We win some on not having to do boundary checks on every element, but lose some on the copying. The copying ends up being too expensive, an alternative implementation would be:
template <class Tuple,
class T = std::decay_t<std::tuple_element_t<0, std::decay_t<Tuple>>>>
std::vector<T> to_vector(Tuple&& tuple)
{
return std::apply([](auto&&... elems) {
using expander = int[];
std::vector<T> result;
result.reserve(sizeof...(elems));
expander{(void(
result.push_back(std::forward<decltype(elems)>(elems))
), 0)...};
return result;
}, std::forward<Tuple>(tuple));
}
See this answer for an explanation of the expander trick. Note that I dropped the leading 0 since we know the pack is non-empty. With C++17, this becomes cleaner with a fold-expression:
return std::apply([](auto&&... elems) {
std::vector<T> result;
result.reserve(sizeof...(elems));
(result.push_back(std::forward<decltype(elems)>(elems)), ...);
return result;
}, std::forward<Tuple>(tuple));
Although still relatively not as nice as the initializer_list constructor. Unfortunate.
Here's one way to do it:
#include <tuple>
#include <algorithm>
#include <vector>
#include <iostream>
template<typename first_type, typename tuple_type, size_t ...index>
auto to_vector_helper(const tuple_type &t, std::index_sequence<index...>)
{
return std::vector<first_type>{
std::get<index>(t)...
};
}
template<typename first_type, typename ...others>
auto to_vector(const std::tuple<first_type, others...> &t)
{
typedef typename std::remove_reference<decltype(t)>::type tuple_type;
constexpr auto s =
std::tuple_size<tuple_type>::value;
return to_vector_helper<first_type, tuple_type>
(t, std::make_index_sequence<s>{});
}
int main()
{
std::tuple<int, int> t{2,3};
std::vector<int> v=to_vector(t);
std::cout << v[0] << ' ' << v[1] << ' ' << v.size() << std::endl;
return 0;
}
Although, this doesn't answer the question completely, This still might be suitable in some cases. Only when the number of elements in tuple is around 5, 6. (And you know the size).
tuple<int, int, int, int> a = make_tuple(1, 2, 3, 4);
auto [p, q, r, s] = a;
vector<int> arr(p, q, r, s); // Now, arr has the same elements as in tuple a
Note that, this is C++ 17 feature. More info here

(C++) Template to check whether an object is in a vector/array/list/...?

Is it possible to create a template in C++(11) for a function to check whether an object is contained in either a std::vector, std::array or std::list (and possibly even more container types)?
What I have by now:
typedef std::shared_ptr<Tag> SharedTag;
typedef std::vector<SharedTag> TagList;
bool
Tag::isIn(const TagList& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
}
Tag is a normal class. The comparison, of course, should be done t == this, which will be an operator== later on. I did not include this here for simplicity.
So, is it possible to write the upper code only once (without the typedef's though,) for std::vector, std::array, std::list(, maybe for std::set) and so on?
I couldn't find a base-type of all these classes,... which would be my first idea...
Option 1 (good): just use std::find directly:
std::vector<int> v; // populate v however you want
std::vector<int>::const_iterator i = std::find(v.cbegin(), v.cend(), 42);
if (i != v.end()) {
// Now you know 42 is in v
} else {
// Now you know 42 is not in v
}
Option 2 (better): wrap std::find in a helper function:
template <typename Container, typename Value>
bool contains(const Container& c, const Value& v)
{
return std::find(std::begin(c), std::end(c), v) != std::begin(c);
}
// Example usage:
std::vector<int> v; // populate v however you want
if (contains(v, 42)) {
// You now know v contains 42
}
Option 3 (best): use the find method of containers that provide one (which is faster for sorted containers, like set), and std::find for containers that don't provide one:
// If you want to know why I added the int and long parameter,
// see this answer here: http://stackoverflow.com/a/9154394/1287251
template <typename Container, typename Value>
inline auto contains(const Container& c, const Value& v, int) -> decltype(c.find(v), bool()) {
return c.find(v) != std::end(c);
}
template <typename Container, typename Value>
inline bool contains(const Container& c, const Value& v, long) {
return std::find(std::begin(c), std::end(c), v) != std::end(c);
}
template <typename Container, typename Value>
bool contains(const Container& c, const Value& v) {
return contains(c, v, 0);
}
// Example usage:
std::set<int> s; // populate s however you want
if (contains(s, 42)) {
// You now know s contains 42
}
Of course, you could write std::find yourself, but you might as well use it.
You may use template:
typedef std::shared_ptr<Tag> SharedTag;
template <typename Container>
bool Tag::isIn(const Container& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
}
That requires that Container is a container of something convertible to SharedTag.
There is no common base-type between those containers. That's just not the way the STL library works, it is based on templates and generic programming principles.
So, if you want to implement the function once for all containers, you would have to make it a template. Here is a basic form:
template <typename TagContainer>
bool Tag::isIn(const TagContainer& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
};
But this has the problem that you could technically pass anything to this function that isn't actually a container of SharedTag, so, to solve this issue, you could use a trick called Sfinae to enforce that rule:
template <typename TagContainer>
typename std::enable_if< std::is_same< SharedTag, typename TagContainer::value_type >::value,
bool >::type Tag::isIn(const TagContainer& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
};
Which kind of ugly, but it works.
There is still one problem though. I suspect that your Tag class is a normal non-template class, which means that you are probably implementing it in a cpp file, but templates need to be implemented in the header file (because function templates need to have their implementation visible to the compiler to generate a new concrete version of it for each type that you call it with).
One way to avoid this problem is to provide a number of overloaded non-template functions for each container you want to support, and then, under-the-hood, you call a local function template, and in this case, you don't need the sfinae trick to constrain it, since it is already limited to the set of overloads that you provided. Something like this:
template <typename TagContainer>
bool Tag::isIn_impl(const TagContainer& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
};
bool Tag::isIn(const std::list<SharedTag>& lst) {
return isIn_impl(lst);
};
bool Tag::isIn(const std::vector<SharedTag>& lst) {
return isIn_impl(lst);
};
bool Tag::isIn(const std::set<SharedTag>& lst) {
return isIn_impl(lst);
};
Note that the isIn_impl is a member function template that should be declared in the header file, in the private section of the class, and can safely be defined in the cpp file, because that cpp file is the only place where that function template is called from.
The obvious issue with that solution is that you have to manually provide every overload that you want to support, which means that it isn't very "scalable" in the future, but in real-life, there probably aren't that many containers that you'd want to support. If you want the full generality, you really have to use the template approach (unless you want to do type-erasure on the container... but that's a bit beyond the scope of what I'm willing to explain here).
You can use a nested variadic template to achieve this. Here is a handy demo: note the magic part, template <template <typename...> class V, typename E>. A variadic template is necessary because vector, list &co. all have a different number of template parameters (allocator, comparator etc.) for which a default value is supplied by the STL.
#include <vector>
#include <string>
#include <memory>
#include <algorithm>
#include <list>
#include <set>
#include <iostream>
class Tag {
public:
Tag(const std::string &n): name(n) {}
template <template <typename...> class V, typename E>
bool isIn(const V<E> &lst) {
return std::any_of(lst.begin(), lst.end(), [this](const E &t) {
return t.name == this->name;
});
}
private:
std::string name;
};
typedef std::shared_ptr<Tag> SharedTag;
typedef std::vector<SharedTag> TagList;
int main() {
Tag t("foo");
// Set needs some extra bits to work (a `<` operator etc.)
//std::set<Tag> a = {Tag("foo"), Tag("bar")};
std::vector<Tag> b = {Tag("foo"), Tag("bar")};
std::list<Tag> c = {Tag("foo"), Tag("bar")};
//std::cout << t.isIn(a) << std::endl;
std::cout << t.isIn(b) << std::endl;
std::cout << t.isIn(c) << std::endl;
}

C++: select argmax over vector of classes w.r.t. arbitrary expression

I have trouble describing my problem so I'll give an example:
I have a class description that has a couple of variables in it, for example:
class A{
float a, b, c, d;
}
Now, I maintain a vector<A> that contains many of these classes. What I need to do very very often is to find the object inside this vector that satisfies that one of it's parameters is maximal w.r.t to the others. i.e code looks something like:
int maxi=-1;
float maxa=-1000;
for(int i=0;i<vec.size();i++){
res= vec[i].a;
if(res > maxa) {
maxa= res;
maxi=i;
}
}
return vec[maxi];
However, sometimes I need to find class with maximal a, sometimes with maximal b, sometimes the class with maximal 0.8*a + 0.2*b, sometimes I want a maximal a*VAR + b, where VAR is some variable that is assigned in front, etc. In other words, I need to evaluate an expression for every class, and take the max. I find myself copy-pasting this everywhere, and only changing the single line that defines res.
Is there some nice way to avoid this insanity in C++? What's the neatest way to handle this?
Thank you!
I know this thread is old, but i find it quite useful to implement a powerful argmax function in C++.
However, as far as i can see, all the given examples above rely on std::max_element, which does comparison between the elements (either using a functor or by calling the operator<). this can be slow, if the calculation for each element is expensive. It works well for sorting numbers and handling simple classes, but what if the functor is much more complex? Maybe calculating a heuristic value of a chess position or something else that generate a huge tree etc.
A real argmax, as the thread starter mentioned, would only calculate its arg once, then save it to be compared with the others.
EDIT: Ok i got annoyed and had too much free time, so i created one < C++11 and one C++11 version with r-value references, first the C++11 version:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
template<typename IteratorT, typename HeuristicFunctorT>
IteratorT argmax(IteratorT && it, const IteratorT & end, const HeuristicFunctorT & functor) {
IteratorT best(it++);
typename HeuristicFunctorT::result_type best_value(functor(*best));
for(; it != end; ++it) {
typename HeuristicFunctorT::result_type value(functor(*it));
if (value > best_value) {
best_value = value;
best = it;
}
}
return best;
}
template<typename IteratorT, typename HeuristicFunctorT>
inline IteratorT argmax(const IteratorT & begin, const IteratorT & end, const HeuristicFunctorT & functor) {
return argmax(IteratorT(begin), end, functor);
}
class IntPairFunctor : public std::unary_function< std::pair<int, int>, int > {
public:
int operator() (const std::pair<int, int> & v) const {
return v.first + v.second;
}
};
std::pair<int, int> rand_pair() {
return std::make_pair(rand(), rand());
}
int main(int argc, const char **argv) {
srand(time(NULL));
std::vector< std::pair<int, int> > ints;
std::generate_n(std::back_insert_iterator< std::vector< std::pair<int, int> > >(ints), 1000, rand_pair);
std::vector< std::pair<int, int> >::iterator m (argmax(ints.begin(), ints.end(), IntPairFunctor()));
std::cout << std::endl << "argmax: " << *m << std::endl;
}
The non C++11 version is much simpler, only the template:
template<typename IteratorT, typename HeuristicFunctorT>
IteratorT argmax(IteratorT it, const IteratorT & end, const HeuristicFunctorT & functor) {
IteratorT best(it++);
typename HeuristicFunctorT::result_type best_value(functor(*best));
for(; it != end; ++it) {
typename HeuristicFunctorT::result_type value(functor(*it));
if (value > best_value) {
best_value = value;
best = it;
}
}
return best;
}
Note that neither version requires any template arguments, the only requirement is that the heuristic implements the unary_function class
template <typename F>
struct CompareBy
{
bool operator()(const typename F::argument_type& x,
const typename F::argument_type& y)
{ return f(x) < f(y); }
CompareBy(const F& f) : f(f) {}
private:
F f;
};
template <typename T, typename U>
struct Member : std::unary_function<U, T>
{
Member(T U::*ptr) : ptr(ptr) {}
const T& operator()(const U& x) { return x.*ptr; }
private:
T U::*ptr;
};
template <typename F>
CompareBy<F> by(const F& f) { return CompareBy<F>(f); }
template <typename T, typename U>
Member<T, U> mem_ptr(T U::*ptr) { return Member<T, U>(ptr); }
You need to include <functional> for this to work. Now use, from header <algorithm>
std::max_element(v.begin(), v.end(), by(mem_ptr(&A::a)));
or
double combination(A x) { return 0.2 * x.a + 0.8 * x.b; }
and
std::max_element(v.begin(), v.end(), by(std::fun_ptr(combination)));
or even
struct combination : std::unary_function<A, double>
{
combination(double x, double y) : x(x), y(y) {}
double operator()(const A& u) { return x * u.a + y * u.b; }
private:
double x, y;
};
with
std::max_element(v.begin(), v.end(), by(combination(0.2, 0.8)));
to compare by a member or by linear combinations of a and b members. I split the comparer in two because the mem_ptr thing is damn useful and worth being reused. The return value of std::max_element is an iterator to the maximum value. You can dereference it to get the max element, or you can use std::distance(v.begin(), i) to find the corresponding index (include <iterator> first).
See http://codepad.org/XQTx0vql for the complete code.
This is what functors and STL are made for:
// A class whose objects perform custom comparisons
class my_comparator
{
public:
explicit my_comparator(float c1, float c2) : c1(c1), c2(c2) {}
// std::max_element calls this on pairs of elements
bool operator() (const A &x, const A &y) const
{
return (x.a*c1 + x.b*c2) < (y.a*c1 + y.b*c2);
}
private:
const float c1, c2;
};
// Returns the "max" element in vec
*std::max_element(vec.begin(), vec.end(), my_comparator(0.8,0.2));
Is the expression always linear? You could pass in an array of four coefficients. If you need to support arbitrary expressions, you'll need a functor, but if it's just an affine combination of the four fields then there's no need for all that complexity.
You can use the std::max_element algorithm with a custom comparator.
It's easy to write the comparator if your compiler supports lambda expressions.
If it doesn't, you can write a custom comparator functor. For the simple case of just comparing a single member, you can write a generic "member comparator" function object, which would look something like this:
template <typename MemberPointer>
struct member_comparator
{
MemberPointer p_;
member_comparator(MemberPointer p) : p_(p) { }
template <typename T>
bool operator()(const T& lhs, const T& rhs) const
{
return lhs.*p_ < rhs.*p_;
}
};
template <typename MemberPointer>
member_comparator<MemberPointer> make_member_comparator(MemberPointer p)
{
return member_comparator<MemberPointer>(p);
}
used as:
// returns an iterator to the element that has the maximum 'd' member:
std::max_element(v.begin(), v.end(), make_member_comparator(&A::d));
You could use the std::max_element STL algorithm providing a custom comparison predicate each time.
With C++0x you can even use a lambda function for it for maximum conciseness:
auto maxElement=*std::max_element(vector.begin(), vector.end(), [](const A& Left, const A& Right) {
return (0.8*Left.a + 0.2*Left.b)<(0.8*Right.a + 0.2*Right.b);
});
Sample of using max_element/min_element with custom functor
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
struct A{
float a, b, c, d;
};
struct CompareA {
bool operator()(A const & Left, A const & Right) const {
return Left.a < Right.a;
}
};
int main() {
vector<A> vec;
vec.resize(3);
vec[0].a = 1;
vec[1].a = 2;
vec[2].a = 1.5;
vector<A>::iterator it = std::max_element(vec.begin(), vec.end(), CompareA());
cout << "Largest A: " << it->a << endl;
it = std::min_element(vec.begin(), vec.end(), CompareA());
cout << "Smallest A: " << it->a << endl;
}

Getting a list of values from a map

Is there an stl way to get a list of values from a map?
i.e, I have:
std::map<A,B> myMap;
and I would like a function that will return just the list of values, i.e, std::list<B> (or set for that matter.
Is there a built-in stl way to do this?
A map element is defined as a map::value_type, and the type of it is a pair<A,B>. first is the key and second is the value. You can write a functor to extract second from a value_type, and copy that in to a vector (or a list, or whatever you want.) The best way to do the copying is to use transform, which does just what its name implies: it takes a value of one type and transforms it to a different type of value.
Here's a complete working example:
#include <cstdlib>
#include <map>
#include <string>
#include <algorithm>
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
typedef map<unsigned, string> MyMap;
MyMap my_map;
struct get_second : public std::unary_function<MyMap::value_type, string>
{
string operator()(const MyMap::value_type& value) const
{
return value.second;
}
};
int main()
{
my_map[1] = "one";
my_map[2] = "two";
my_map[3] = "three";
my_map[4] = "four";
my_map[5] = "five";
// get a vector of values
vector<string> my_vals;
transform(my_map.begin(), my_map.end(), back_inserter(my_vals), get_second() );
// dump the list
copy( my_vals.begin(), my_vals.end(), ostream_iterator<string>(cout, "\n"));
}
EDIT:
If you have a compiler that supports C++0x lambdas, you can eliminate the functor entirely. This is very useful for making code more readable and, arguable, easier to maintain since you don't end up with dozens of little one-off functors floating around in your codebase. Here's how you would change the code above to use a lambda:
transform(my_map.begin(), my_map.end(), back_inserter(my_vals), [](const MyMap::value_type& val){return val.second;} );
There's nothing built in, no. It's simple enough to write your own function, though: Iterate over the map. The iterator will give you a pair<A, B>. Add each second value to the result list.
You can't just "get" such a list because there is no pre-existing list stored anywhere in the guts, but you can build one:
typedef std::map<A,B> myMapType;
myMapType myMap;
std::list<B> valueList;
for (myMapType::const_iterator it=myMap.begin(); it!=myMap.end(); ++it) {
valueList.push_back( it->second );
}
Or if you really like the more STL way:
class GetSecond {
template<typename T1, typename T2>
const T2& operator()( const std::pair<T1,T2>& key_val ) const
{ return key_val.second; }
};
typedef std::map<A,B> myMapType;
myMapType myMap;
std::list<B> valueList;
std::transform(myMap.begin(), myMap.end(), std::back_inserter(valueList),
GetSecond());
One of many "built-in" ways is of course the most obvious one. Just iterate over all pair elements, which are ordered by key (pair::first), and add the value (pair::second) to a new container, which you can construct with the correct capacity to get rid of excess allocations during the iteration and adding.
Just a note: std::list is seldom the container you actually want to be using. Unless, of course, you really, really do need its specific features.
Sure.
std::list<B> list;
std::for_each(myMap.begin(), myMap.end(), [&](const std::pair<const A, B>& ref) {
list.push_back(ref.second);
});
If you don't have a C++0x compiler, first you have my sympathies, and second, you will need to build a quick function object for this purpose.
You can use boost's transform_iterator: http://www.boost.org/doc/libs/1_64_0/libs/iterator/doc/transform_iterator.html
struct GetSecond {
template <typename K, typename T>
const T& operator()(const std::pair<K, T> & p) const { return p.second; }
template <typename K, typename T>
T& operator()(std::pair<K, T> & p) const { return p.second; }
};
template <typename MapType>
auto begin_values(MapType& m) -> decltype(boost::make_transform_iterator(m.begin(), GetSecond())) {
return boost::make_transform_iterator(m.begin(), GetSecond());
}
template <typename MapType>
auto end_values(MapType& m) -> decltype(boost::make_transform_iterator(m.end(), GetSecond())) {
return boost::make_transform_iterator(m.end(), GetSecond());
}
template <typename MapType>
struct MapValues {
MapType & m;
MapValues(MapType & m) : m(m) {}
typedef decltype(begin_values(m)) iterator;
iterator begin() { return begin_values(m); }
iterator end() { return end_values(m); }
};
template <typename MapType>
MapValues<MapType> get_values(MapType & m) {
return MapValues<MapType>(m);
}
int main() {
std::map<int, double> m;
m[0] = 1.0;
m[10] = 2.0;
for (auto& x : get_values(m)) {
std::cout << x << ',';
x += 1;
}
std::cout << std::endl;
const std::map<int, double> mm = m;
for (auto& x : get_values(mm)) {
std::cout << x << ',';
}
std::cout << std::endl;
}