This question already has answers here:
How can I sort two vectors in the same way, with criteria that uses only one of the vectors?
(9 answers)
Closed 11 months ago.
The best example I've got is that I want to sort Names based on their Score.
vector <string> Names {"Karl", "Martin", "Paul", "Jennie"};
vector <int> Score{45, 5, 14, 24};
So if I sort the score to {5, 14, 24, 45}, the names should also be sorted based on their score.
An alternative to consolidating the names and scores into a single structure is to create an index list and sort that:
std::vector<int> indices(Names.size());
std::iota(indices.begin(), indices.end(), 0);
std::sort(indices.begin(), indices.end(),
[&](int A, int B) -> bool {
return Score[A] < Score[B];
});
Now indices can be used to index Names and Scores in the desired sorted order.
As already suggested in other answers: Combining the name and the score of each individual is likely the simplest solution.
Generically, this can be achieved with what is sometimes referred to as a "zip" operation: Combining two vectors into a vector of pairs - along with a corresponding "unzip".
Implemented generically, this may look as follows:
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
// Fill the zipped vector with pairs consisting of the
// corresponding elements of a and b. (This assumes
// that the vectors have equal length)
template <typename A, typename B>
void zip(
const std::vector<A> &a,
const std::vector<B> &b,
std::vector<std::pair<A,B>> &zipped)
{
for(size_t i=0; i<a.size(); ++i)
{
zipped.push_back(std::make_pair(a[i], b[i]));
}
}
// Write the first and second element of the pairs in
// the given zipped vector into a and b. (This assumes
// that the vectors have equal length)
template <typename A, typename B>
void unzip(
const std::vector<std::pair<A, B>> &zipped,
std::vector<A> &a,
std::vector<B> &b)
{
for(size_t i=0; i<a.size(); i++)
{
a[i] = zipped[i].first;
b[i] = zipped[i].second;
}
}
int main(int argc, char* argv[])
{
std::vector<std::string> names {"Karl", "Martin", "Paul", "Jennie"};
std::vector<int> score {45, 5, 14, 24};
// Zip the vectors together
std::vector<std::pair<std::string,int>> zipped;
zip(names, score, zipped);
// Sort the vector of pairs
std::sort(std::begin(zipped), std::end(zipped),
[&](const auto& a, const auto& b)
{
return a.second > b.second;
});
// Write the sorted pairs back to the original vectors
unzip(zipped, names, score);
for(size_t i=0; i<names.size(); i++)
{
std::cout << names[i] << " : " << score[i] << std::endl;
}
return 0;
}
Best way to do this would be to have a struct which combines the names with their scores and have one vector.
struct Person
{
std::string Name;
int Score;
};
Then you can declare your vector:
std::vector<Person> people{ { "Karl", 45 }, { "Martin", 5 }, { "Paul", 14 } };
And sorting it is easy with std::sort from <algorithm>:
std::sort(people.begin(), people.end(),
[](const auto& i, const auto& j) { return i.Score < j.Score; } );
Or you can change the lambda if you want to sort in descending order:
std::sort(people.begin(), people.end(),
[](const auto& i, const auto& j) { return i.Score > j.Score; } );
If you cannot merge the data into a vector of pairs or struct with both, you could create a vector of iterators, or the indexes from 0 to size-1. Then sort this using a custom comparator. Finally, create a new vector, populating it using the iterators or indexes.
template<class T1, class A1, class T2, class A2>
std::vector<T1, A1> sort_by(
std::vector<T1,A1> const& vin, std::vector<T2,A2> const& keys
){
std::vector<std::size_t> is;
is.reserve(vin.size());
for (auto&& unused:keys)
is.push_back(is.size());
std::sort(begin(is),end(is),[&](std::size_t l, std::size_t r){
return keys[l]<keys[r];
});
std::vector<T1, A1> r;
r.reserve(vin.size());
for(std::size_t i:is)
r.push_back(vin[i]);
return r;
}
So many asked this question and nobody came up with a satisfactory answer. Here is a std::sort helper that enables to sort two vectors simultaneously, taking into account the values of only one vector. This solution is based on a custom RadomIt (random iterator), and operates directly on the original vector data, without temporary copies, structure rearrangement or additional indices:
namespace std {
namespace sort_helper {
template <typename _Data, typename _Order>
struct value_reference_t;
template <typename _Data, typename _Order>
struct value_t {
_Data data;
_Order val;
inline value_t(_Data _data, _Order _val) : data(_data), val(_val) {}
inline value_t(const value_reference_t<_Data,_Order>& rhs);
};
template <typename _Data, typename _Order>
struct value_reference_t {
_Data* pdata;
_Order* pval;
value_reference_t(_Data* _itData, _Order* _itVal) : pdata(_itData), pval(_itVal) {}
inline value_reference_t& operator = (const value_reference_t& rhs) { *pdata = *rhs.pdata; *pval = *rhs.pval; return *this; }
inline value_reference_t& operator = (const value_t<_Data,_Order>& rhs) { *pdata = rhs.data; *pval = rhs.val; return *this; }
inline bool operator < (const value_reference_t& rhs) { return *pval < *rhs.pval; }
};
template <typename _Data, typename _Order>
struct value_iterator_t :
iterator< random_access_iterator_tag, value_t<_Data,_Order>, ptrdiff_t, value_t<_Data,_Order>*, value_reference_t<_Data,_Order> >
{
_Data* itData;
_Order* itVal;
value_iterator_t(_Data* _itData, _Order* _itVal) : itData(_itData), itVal(_itVal) {}
inline ptrdiff_t operator - (const value_iterator_t& rhs) const { return itVal - rhs.itVal; }
inline value_iterator_t operator + (ptrdiff_t off) const { return value_iterator_t(itData + off, itVal + off); }
inline value_iterator_t operator - (ptrdiff_t off) const { return value_iterator_t(itData - off, itVal - off); }
inline value_iterator_t& operator ++ () { ++itData; ++itVal; return *this; }
inline value_iterator_t& operator -- () { --itData; --itVal; return *this; }
inline value_iterator_t operator ++ (int) { return value_iterator_t(itData++, itVal++); }
inline value_iterator_t operator -- (int) { return value_iterator_t(itData--, itVal--); }
inline value_t<_Data,_Order> operator * () const { return value_t<_Data,_Order>(*itData, *itVal); }
inline value_reference_t<_Data,_Order> operator * () { return value_reference_t<_Data,_Order>(itData, itVal); }
inline bool operator < (const value_iterator_t& rhs) const { return itVal < rhs.itVal; }
inline bool operator == (const value_iterator_t& rhs) const { return itVal == rhs.itVal; }
inline bool operator != (const value_iterator_t& rhs) const { return itVal != rhs.itVal; }
};
template <typename _Data, typename _Order>
inline value_t<_Data,_Order>::value_t(const value_reference_t<_Data,_Order>& rhs)
: data(*rhs.pdata), val(*rhs.pval) {}
template <typename _Data, typename _Order>
bool operator < (const value_t<_Data,_Order>& lhs, const value_reference_t<_Data,_Order>& rhs) {
return lhs.val < *rhs.pval; }
template <typename _Data, typename _Order>
bool operator < (const value_reference_t<_Data,_Order>& lhs, const value_t<_Data,_Order>& rhs) {
return *lhs.pval < rhs.val; }
template <typename _Data, typename _Order>
void swap(value_reference_t<_Data,_Order> lhs, value_reference_t<_Data,_Order> rhs) {
std::swap(*lhs.pdata, *rhs.pdata);
std::swap(*lhs.pval, *rhs.pval); }
} // namespace sort_helper
} // namespace std
And this is an usage example that sorts both Names and Age based on Age values, employing standard std::sort:
char* Names[] = { "Karl", "Paul", "Martin", "Jennie" };
int Age[] = { 45, 14, 5, 24 };
typedef std::sort_helper::value_iterator_t<char*,int> IndexIt;
std::sort(IndexIt(Names, Age), IndexIt(Names+4, Age+4));
sorted to:
{ "Martin", "Paul", "Jennie", "Karl" };
{ 5, 14, 24, 45 };
Code tested on Visual Studio 2017 and GCC 5.4.0.
One way you could do this would be to store the Names and Scores in a single data structure such as a std::vector<std::pair<std::string,int>> and then sorting can be done as follows:
#include <algorithm>
#include <vector>
#include <string>
#include <utility>
//...
std::vector<std::pair<std::string, int>> names_scores_vec;
// ... populate names_scores_vec...
// lambda for sorting, change to > for descending order
auto sort_by_scores = [](const std::pair<string,int>& _lhs,
const std::pair<string,int>& _rhs) { return _lhs.second < _rhs.second; };
std::sort(names_scores_vec.begin(), names_scores_vec.end(), sort_by_scores);
Alternatively, use storage such as a std::map or std::multimap if you want repeated keys (i.e. repeated names allowed).
Couldn't this be done through a custom iterator type?
EDIT:
What I'm thinking in its simplest form - sorting a pair of vectors based on the first one - is to have an iterator whose functions such as dereferencing, subscripting, member access and equality and ordering comparisons would call the corresponding functions on the first iterator, all other functions (copy, arithmetics, swap, ...) acting on both iterators.
template <typename Driver, typename Passenger>
struct duo_iterator { . . . };
template <typename D, typename P>
auto make_duo_iterator(D d, P p) -> duo_iterator<D, P> { . . . }
sort(make_duo_iterator(begin(v1), begin(v2)),
make_duo_iterator(end(v1), end(v2)));
The iterator could be extended into a multi_iterator to work with any reordering algorithm, pointing into any number of extra piggybacking sequences.
It could be a fun little project. Or maybe something similar already exists, in Boost or elsewhere.
EDIT2:
Forget the above.
Eric Niebler's Range-v3 library has a view::zip wrapper that "Given N ranges, return a new range where Mth element is the result of calling make_tuple on the Mth elements of all N ranges."
Sorting the range with a predicate on the first element of the tuples might just do the trick.
Related
This question already has answers here:
How can I sort two vectors in the same way, with criteria that uses only one of the vectors?
(9 answers)
Closed 11 months ago.
The best example I've got is that I want to sort Names based on their Score.
vector <string> Names {"Karl", "Martin", "Paul", "Jennie"};
vector <int> Score{45, 5, 14, 24};
So if I sort the score to {5, 14, 24, 45}, the names should also be sorted based on their score.
An alternative to consolidating the names and scores into a single structure is to create an index list and sort that:
std::vector<int> indices(Names.size());
std::iota(indices.begin(), indices.end(), 0);
std::sort(indices.begin(), indices.end(),
[&](int A, int B) -> bool {
return Score[A] < Score[B];
});
Now indices can be used to index Names and Scores in the desired sorted order.
As already suggested in other answers: Combining the name and the score of each individual is likely the simplest solution.
Generically, this can be achieved with what is sometimes referred to as a "zip" operation: Combining two vectors into a vector of pairs - along with a corresponding "unzip".
Implemented generically, this may look as follows:
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
// Fill the zipped vector with pairs consisting of the
// corresponding elements of a and b. (This assumes
// that the vectors have equal length)
template <typename A, typename B>
void zip(
const std::vector<A> &a,
const std::vector<B> &b,
std::vector<std::pair<A,B>> &zipped)
{
for(size_t i=0; i<a.size(); ++i)
{
zipped.push_back(std::make_pair(a[i], b[i]));
}
}
// Write the first and second element of the pairs in
// the given zipped vector into a and b. (This assumes
// that the vectors have equal length)
template <typename A, typename B>
void unzip(
const std::vector<std::pair<A, B>> &zipped,
std::vector<A> &a,
std::vector<B> &b)
{
for(size_t i=0; i<a.size(); i++)
{
a[i] = zipped[i].first;
b[i] = zipped[i].second;
}
}
int main(int argc, char* argv[])
{
std::vector<std::string> names {"Karl", "Martin", "Paul", "Jennie"};
std::vector<int> score {45, 5, 14, 24};
// Zip the vectors together
std::vector<std::pair<std::string,int>> zipped;
zip(names, score, zipped);
// Sort the vector of pairs
std::sort(std::begin(zipped), std::end(zipped),
[&](const auto& a, const auto& b)
{
return a.second > b.second;
});
// Write the sorted pairs back to the original vectors
unzip(zipped, names, score);
for(size_t i=0; i<names.size(); i++)
{
std::cout << names[i] << " : " << score[i] << std::endl;
}
return 0;
}
Best way to do this would be to have a struct which combines the names with their scores and have one vector.
struct Person
{
std::string Name;
int Score;
};
Then you can declare your vector:
std::vector<Person> people{ { "Karl", 45 }, { "Martin", 5 }, { "Paul", 14 } };
And sorting it is easy with std::sort from <algorithm>:
std::sort(people.begin(), people.end(),
[](const auto& i, const auto& j) { return i.Score < j.Score; } );
Or you can change the lambda if you want to sort in descending order:
std::sort(people.begin(), people.end(),
[](const auto& i, const auto& j) { return i.Score > j.Score; } );
If you cannot merge the data into a vector of pairs or struct with both, you could create a vector of iterators, or the indexes from 0 to size-1. Then sort this using a custom comparator. Finally, create a new vector, populating it using the iterators or indexes.
template<class T1, class A1, class T2, class A2>
std::vector<T1, A1> sort_by(
std::vector<T1,A1> const& vin, std::vector<T2,A2> const& keys
){
std::vector<std::size_t> is;
is.reserve(vin.size());
for (auto&& unused:keys)
is.push_back(is.size());
std::sort(begin(is),end(is),[&](std::size_t l, std::size_t r){
return keys[l]<keys[r];
});
std::vector<T1, A1> r;
r.reserve(vin.size());
for(std::size_t i:is)
r.push_back(vin[i]);
return r;
}
So many asked this question and nobody came up with a satisfactory answer. Here is a std::sort helper that enables to sort two vectors simultaneously, taking into account the values of only one vector. This solution is based on a custom RadomIt (random iterator), and operates directly on the original vector data, without temporary copies, structure rearrangement or additional indices:
namespace std {
namespace sort_helper {
template <typename _Data, typename _Order>
struct value_reference_t;
template <typename _Data, typename _Order>
struct value_t {
_Data data;
_Order val;
inline value_t(_Data _data, _Order _val) : data(_data), val(_val) {}
inline value_t(const value_reference_t<_Data,_Order>& rhs);
};
template <typename _Data, typename _Order>
struct value_reference_t {
_Data* pdata;
_Order* pval;
value_reference_t(_Data* _itData, _Order* _itVal) : pdata(_itData), pval(_itVal) {}
inline value_reference_t& operator = (const value_reference_t& rhs) { *pdata = *rhs.pdata; *pval = *rhs.pval; return *this; }
inline value_reference_t& operator = (const value_t<_Data,_Order>& rhs) { *pdata = rhs.data; *pval = rhs.val; return *this; }
inline bool operator < (const value_reference_t& rhs) { return *pval < *rhs.pval; }
};
template <typename _Data, typename _Order>
struct value_iterator_t :
iterator< random_access_iterator_tag, value_t<_Data,_Order>, ptrdiff_t, value_t<_Data,_Order>*, value_reference_t<_Data,_Order> >
{
_Data* itData;
_Order* itVal;
value_iterator_t(_Data* _itData, _Order* _itVal) : itData(_itData), itVal(_itVal) {}
inline ptrdiff_t operator - (const value_iterator_t& rhs) const { return itVal - rhs.itVal; }
inline value_iterator_t operator + (ptrdiff_t off) const { return value_iterator_t(itData + off, itVal + off); }
inline value_iterator_t operator - (ptrdiff_t off) const { return value_iterator_t(itData - off, itVal - off); }
inline value_iterator_t& operator ++ () { ++itData; ++itVal; return *this; }
inline value_iterator_t& operator -- () { --itData; --itVal; return *this; }
inline value_iterator_t operator ++ (int) { return value_iterator_t(itData++, itVal++); }
inline value_iterator_t operator -- (int) { return value_iterator_t(itData--, itVal--); }
inline value_t<_Data,_Order> operator * () const { return value_t<_Data,_Order>(*itData, *itVal); }
inline value_reference_t<_Data,_Order> operator * () { return value_reference_t<_Data,_Order>(itData, itVal); }
inline bool operator < (const value_iterator_t& rhs) const { return itVal < rhs.itVal; }
inline bool operator == (const value_iterator_t& rhs) const { return itVal == rhs.itVal; }
inline bool operator != (const value_iterator_t& rhs) const { return itVal != rhs.itVal; }
};
template <typename _Data, typename _Order>
inline value_t<_Data,_Order>::value_t(const value_reference_t<_Data,_Order>& rhs)
: data(*rhs.pdata), val(*rhs.pval) {}
template <typename _Data, typename _Order>
bool operator < (const value_t<_Data,_Order>& lhs, const value_reference_t<_Data,_Order>& rhs) {
return lhs.val < *rhs.pval; }
template <typename _Data, typename _Order>
bool operator < (const value_reference_t<_Data,_Order>& lhs, const value_t<_Data,_Order>& rhs) {
return *lhs.pval < rhs.val; }
template <typename _Data, typename _Order>
void swap(value_reference_t<_Data,_Order> lhs, value_reference_t<_Data,_Order> rhs) {
std::swap(*lhs.pdata, *rhs.pdata);
std::swap(*lhs.pval, *rhs.pval); }
} // namespace sort_helper
} // namespace std
And this is an usage example that sorts both Names and Age based on Age values, employing standard std::sort:
char* Names[] = { "Karl", "Paul", "Martin", "Jennie" };
int Age[] = { 45, 14, 5, 24 };
typedef std::sort_helper::value_iterator_t<char*,int> IndexIt;
std::sort(IndexIt(Names, Age), IndexIt(Names+4, Age+4));
sorted to:
{ "Martin", "Paul", "Jennie", "Karl" };
{ 5, 14, 24, 45 };
Code tested on Visual Studio 2017 and GCC 5.4.0.
One way you could do this would be to store the Names and Scores in a single data structure such as a std::vector<std::pair<std::string,int>> and then sorting can be done as follows:
#include <algorithm>
#include <vector>
#include <string>
#include <utility>
//...
std::vector<std::pair<std::string, int>> names_scores_vec;
// ... populate names_scores_vec...
// lambda for sorting, change to > for descending order
auto sort_by_scores = [](const std::pair<string,int>& _lhs,
const std::pair<string,int>& _rhs) { return _lhs.second < _rhs.second; };
std::sort(names_scores_vec.begin(), names_scores_vec.end(), sort_by_scores);
Alternatively, use storage such as a std::map or std::multimap if you want repeated keys (i.e. repeated names allowed).
Couldn't this be done through a custom iterator type?
EDIT:
What I'm thinking in its simplest form - sorting a pair of vectors based on the first one - is to have an iterator whose functions such as dereferencing, subscripting, member access and equality and ordering comparisons would call the corresponding functions on the first iterator, all other functions (copy, arithmetics, swap, ...) acting on both iterators.
template <typename Driver, typename Passenger>
struct duo_iterator { . . . };
template <typename D, typename P>
auto make_duo_iterator(D d, P p) -> duo_iterator<D, P> { . . . }
sort(make_duo_iterator(begin(v1), begin(v2)),
make_duo_iterator(end(v1), end(v2)));
The iterator could be extended into a multi_iterator to work with any reordering algorithm, pointing into any number of extra piggybacking sequences.
It could be a fun little project. Or maybe something similar already exists, in Boost or elsewhere.
EDIT2:
Forget the above.
Eric Niebler's Range-v3 library has a view::zip wrapper that "Given N ranges, return a new range where Mth element is the result of calling make_tuple on the Mth elements of all N ranges."
Sorting the range with a predicate on the first element of the tuples might just do the trick.
I know how to sort a vector of pairs, but how do you sort a pair of vectors? I can think of writing a custom "virtual" iterator over a pair of vectors and sorting that, but that seems quite complex. Is there an easier way? Is there one in C++03? I would like to use std::sort.
This problem arises when processing some data generated in hardware, where a pair of arrays makes more sense than array of pairs (since then there would be all kinds of stride and alignment problems). I realize that otherwise keeping a pair of vector instead of a vector of pairs would be a design flaw (the structure of arrays problem). I'm looking for a fast solution, copying the data to a vector of pairs and then back (I will return it to the HW to do more processing) is not an option.
Example:
keys = {5, 2, 3, 1, 4}
values = {a, b, d, e, c}
and after sorting (by the first vector):
keys = {1, 2, 3, 4, 5}
values = {e, b, d, c, a}
I refer to a "pair of vectors" as the pair of keys and values (stored as e.g. std::pair<std::vector<size_t>, std::vector<double> >). The vectors have the same length.
Let's make a sort/permute iterator, so that we can just say:
int keys[] = { 5, 2, 3, 1, 4 };
char vals[] = { 'a', 'b', 'd', 'e', 'c' };
std::sort(make_dual_iter(begin(keys), begin(vals)),
make_dual_iter(end(keys), end(vals)));
// output
std::copy(begin(keys), end(keys), std::ostream_iterator<int> (std::cout << "\nKeys:\t", "\t"));
std::copy(begin(vals), end(vals), std::ostream_iterator<char>(std::cout << "\nValues:\t", "\t"));
See it Live On Coliru, printing
Keys: 1 2 3 4 5
Values: e b d c a
Based on the idea here, I've implemented this:
namespace detail {
template <class KI, class VI> struct helper {
using value_type = boost::tuple<typename std::iterator_traits<KI>::value_type, typename std::iterator_traits<VI>::value_type>;
using ref_type = boost::tuple<typename std::iterator_traits<KI>::reference, typename std::iterator_traits<VI>::reference>;
using difference_type = typename std::iterator_traits<KI>::difference_type;
};
}
template <typename KI, typename VI, typename H = typename detail::helper<KI, VI> >
class dual_iter : public boost::iterator_facade<dual_iter<KI, VI>, // CRTP
typename H::value_type, std::random_access_iterator_tag, typename H::ref_type, typename H::difference_type>
{
public:
dual_iter() = default;
dual_iter(KI ki, VI vi) : _ki(ki), _vi(vi) { }
KI _ki;
VI _vi;
private:
friend class boost::iterator_core_access;
void increment() { ++_ki; ++_vi; }
void decrement() { --_ki; --_vi; }
bool equal(dual_iter const& other) const { return (_ki == other._ki); }
typename detail::helper<KI, VI>::ref_type dereference() const {
return (typename detail::helper<KI, VI>::ref_type(*_ki, *_vi));
}
void advance(typename H::difference_type n) { _ki += n; _vi += n; }
typename H::difference_type distance_to(dual_iter const& other) const { return ( other._ki - _ki); }
};
Now the factory function is simply:
template <class KI, class VI>
dual_iter<KI, VI> make_dual_iter(KI ki, VI vi) { return {ki, vi}; }
Note I've been a little lazy by using boost/tuples/tuple_comparison.hpp for the sorting. This could pose a problem with stable sort when multiple key values share the same value. However, in this case it's hard to define what is "stable" sort anyways, so I didn't think it important for now.
FULL LISTING
Live On Coliru
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/tuple/tuple_comparison.hpp>
namespace boost { namespace tuples {
// MSVC might not require this
template <typename T, typename U>
inline void swap(boost::tuple<T&, U&> a, boost::tuple<T&, U&> b) noexcept {
using std::swap;
swap(boost::get<0>(a), boost::get<0>(b));
swap(boost::get<1>(a), boost::get<1>(b));
}
} }
namespace detail {
template <class KI, class VI> struct helper {
using value_type = boost::tuple<typename std::iterator_traits<KI>::value_type, typename std::iterator_traits<VI>::value_type>;
using ref_type = boost::tuple<typename std::iterator_traits<KI>::reference, typename std::iterator_traits<VI>::reference>;
using difference_type = typename std::iterator_traits<KI>::difference_type;
};
}
template <typename KI, typename VI, typename H = typename detail::helper<KI, VI> >
class dual_iter : public boost::iterator_facade<dual_iter<KI, VI>, // CRTP
typename H::value_type, std::random_access_iterator_tag, typename H::ref_type, typename H::difference_type>
{
public:
dual_iter() = default;
dual_iter(KI ki, VI vi) : _ki(ki), _vi(vi) { }
KI _ki;
VI _vi;
private:
friend class boost::iterator_core_access;
void increment() { ++_ki; ++_vi; }
void decrement() { --_ki; --_vi; }
bool equal(dual_iter const& other) const { return (_ki == other._ki); }
typename detail::helper<KI, VI>::ref_type dereference() const {
return (typename detail::helper<KI, VI>::ref_type(*_ki, *_vi));
}
void advance(typename H::difference_type n) { _ki += n; _vi += n; }
typename H::difference_type distance_to(dual_iter const& other) const { return ( other._ki - _ki); }
};
template <class KI, class VI>
dual_iter<KI, VI> make_dual_iter(KI ki, VI vi) { return {ki, vi}; }
#include <iostream>
using std::begin;
using std::end;
int main()
{
int keys[] = { 5, 2, 3, 1, 4 };
char vals[] = { 'a', 'b', 'd', 'e', 'c' };
std::sort(make_dual_iter(begin(keys), begin(vals)),
make_dual_iter(end(keys), end(vals)));
std::copy(begin(keys), end(keys), std::ostream_iterator<int> (std::cout << "\nKeys:\t", "\t"));
std::copy(begin(vals), end(vals), std::ostream_iterator<char>(std::cout << "\nValues:\t", "\t"));
}
Just for comparison, this is how much code the split iterator approach requires:
template <class V0, class V1>
class CRefPair { // overrides copy semantics of std::pair
protected:
V0 &m_v0;
V1 &m_v1;
public:
CRefPair(V0 &v0, V1 &v1)
:m_v0(v0), m_v1(v1)
{}
void swap(CRefPair &other)
{
std::swap(m_v0, other.m_v0);
std::swap(m_v1, other.m_v1);
}
operator std::pair<V0, V1>() const // both g++ and msvc sort requires this (to get a pivot)
{
return std::pair<V0, V1>(m_v0, m_v1);
}
CRefPair &operator =(std::pair<V0, V1> v) // both g++ and msvc sort requires this (for insertion sort)
{
m_v0 = v.first;
m_v1 = v.second;
return *this;
}
CRefPair &operator =(const CRefPair &other) // required by g++ (for _GLIBCXX_MOVE)
{
m_v0 = other.m_v0;
m_v1 = other.m_v1;
return *this;
}
};
template <class V0, class V1>
inline bool operator <(std::pair<V0, V1> a, CRefPair<V0, V1> b) // required by both g++ and msvc
{
return a < std::pair<V0, V1>(b); // default pairwise lexicographical comparison
}
template <class V0, class V1>
inline bool operator <(CRefPair<V0, V1> a, std::pair<V0, V1> b) // required by both g++ and msvc
{
return std::pair<V0, V1>(a) < b; // default pairwise lexicographical comparison
}
template <class V0, class V1>
inline bool operator <(CRefPair<V0, V1> a, CRefPair<V0, V1> b) // required by both g++ and msvc
{
return std::pair<V0, V1>(a) < std::pair<V0, V1>(b); // default pairwise lexicographical comparison
}
namespace std {
template <class V0, class V1>
inline void swap(CRefPair<V0, V1> &a, CRefPair<V0, V1> &b)
{
a.swap(b);
}
} // ~std
template <class It0, class It1>
class CPairIterator : public std::random_access_iterator_tag {
public:
typedef typename std::iterator_traits<It0>::value_type value_type0;
typedef typename std::iterator_traits<It1>::value_type value_type1;
typedef std::pair<value_type0, value_type1> value_type;
typedef typename std::iterator_traits<It0>::difference_type difference_type;
typedef /*typename std::iterator_traits<It0>::distance_type*/difference_type distance_type; // no distance_type in g++, only in msvc
typedef typename std::iterator_traits<It0>::iterator_category iterator_category;
typedef CRefPair<value_type0, value_type1> reference;
typedef reference *pointer; // not so sure about this, probably can't be implemented in a meaningful way, won't be able to overload ->
// keep the iterator traits happy
protected:
It0 m_it0;
It1 m_it1;
public:
CPairIterator(const CPairIterator &r_other)
:m_it0(r_other.m_it0), m_it1(r_other.m_it1)
{}
CPairIterator(It0 it0 = It0(), It1 it1 = It1())
:m_it0(it0), m_it1(it1)
{}
reference operator *()
{
return reference(*m_it0, *m_it1);
}
value_type operator *() const
{
return value_type(*m_it0, *m_it1);
}
difference_type operator -(const CPairIterator &other) const
{
assert(m_it0 - other.m_it0 == m_it1 - other.m_it1);
// the iterators always need to have the same position
// (incomplete check but the best we can do without having also begin / end in either vector)
return m_it0 - other.m_it0;
}
bool operator ==(const CPairIterator &other) const
{
assert(m_it0 - other.m_it0 == m_it1 - other.m_it1);
return m_it0 == other.m_it0;
}
bool operator !=(const CPairIterator &other) const
{
return !(*this == other);
}
bool operator <(const CPairIterator &other) const
{
assert(m_it0 - other.m_it0 == m_it1 - other.m_it1);
return m_it0 < other.m_it0;
}
bool operator >=(const CPairIterator &other) const
{
return !(*this < other);
}
bool operator <=(const CPairIterator &other) const
{
return !(other < *this);
}
bool operator >(const CPairIterator &other) const
{
return other < *this;
}
CPairIterator operator +(distance_type d) const
{
return CPairIterator(m_it0 + d, m_it1 + d);
}
CPairIterator operator -(distance_type d) const
{
return *this + -d;
}
CPairIterator &operator +=(distance_type d)
{
return *this = *this + d;
}
CPairIterator &operator -=(distance_type d)
{
return *this = *this + -d;
}
CPairIterator &operator ++()
{
return *this += 1;
}
CPairIterator &operator --()
{
return *this += -1;
}
CPairIterator operator ++(int) // msvc sort actually needs this, g++ does not
{
CPairIterator old = *this;
++ (*this);
return old;
}
CPairIterator operator --(int)
{
CPairIterator old = *this;
-- (*this);
return old;
}
};
template <class It0, class It1>
inline CPairIterator<It0, It1> make_pair_iterator(It0 it0, It1 it1)
{
return CPairIterator<It0, It1>(it0, it1);
}
It is kind of rough around the edges, maybe I'm just bad at overloading the comparisons, but the amount of differences needed to support different implementations of std::sort makes me think the hackish solution might actually be more portable. But the sorting is much nicer:
struct CompareByFirst {
bool operator ()(std::pair<size_t, char> a, std::pair<size_t, char> b) const
{
return a.first < b.first;
}
};
std::vector<char> vv; // filled by values
std::vector<size_t> kv; // filled by keys
std::sort(make_pair_iterator(kv.begin(), vv.begin()),
make_pair_iterator(kv.end(), vv.end()), CompareByFirst());
// nice
And of course it gives the correct result.
Inspired by a comment by Mark Ransom, this is a horrible hack, and an example of how not to do it. I only wrote it for amusement and because I was wondering how complicated would it get. This is not an answer to my question, I will not use this. I just wanted to share a bizarre idea. Please, do not downvote.
Actually, ignoring multithreading, I believe this could be done:
template <class KeyType, class ValueVectorType>
struct MyKeyWrapper { // all is public to save getters
KeyType k;
bool operator <(const MyKeyWrapper &other) const { return k < other.k; }
};
template <class KeyType, class ValueVectorType>
struct ValueVectorSingleton { // all is public to save getters, but kv and vv should be only accessible by getters
static std::vector<MyKeyWrapper<KeyType, ValueVectorType> > *kv;
static ValueVectorType *vv;
static void StartSort(std::vector<MyKeyWrapper<KeyType, ValueVectorType> > &_kv, ValueVectorType &_vv)
{
assert(!kv && !vv); // can't sort two at once (if multithreading)
assert(_kv.size() == _vv.size());
kv = &_kv, vv = &_vv; // not an attempt of an atomic operation
}
static void EndSort()
{
kv = 0, vv = 0; // not an attempt of an atomic operation
}
};
template <class KeyType, class ValueVectorType>
std::vector<MyKeyWrapper<KeyType, ValueVectorType> >
*ValueVectorSingleton<KeyType, ValueVectorType>::kv = 0;
template <class KeyType, class ValueVectorType>
ValueVectorType *ValueVectorSingleton<KeyType, ValueVectorType>::vv = 0;
namespace std {
template <class KeyType, class ValueVectorType>
void swap(MyKeyWrapper<KeyType, ValueVectorType> &a,
MyKeyWrapper<KeyType, ValueVectorType> &b)
{
assert((ValueVectorSingleton<KeyType, ValueVectorType>::vv &&
ValueVectorSingleton<KeyType, ValueVectorType>::kv)); // if this triggers, someone forgot to call StartSort()
ValueVectorType &vv = *ValueVectorSingleton<KeyType, ValueVectorType>::vv;
std::vector<MyKeyWrapper<KeyType, ValueVectorType> > &kv =
*ValueVectorSingleton<KeyType, ValueVectorType>::kv;
size_t ai = &kv.front() - &a, bi = &kv.front() - &b; // get indices in key vector
std::swap(a, b); // swap keys
std::swap(vv[ai], vv[bi]); // and any associated values
}
} // ~std
And sorting as:
std::vector<char> vv; // filled by values
std::vector<MyKeyWrapper<size_t, std::vector<char> > > kv; // filled by keys, casted to MyKeyWrapper
ValueVectorSingleton<size_t, std::vector<char> >::StartSort(kv, vv);
std::sort(kv.begin(), kv.end());
ValueVectorSingleton<size_t, std::vector<char> >::EndSort();
// trick std::sort into using the custom std::swap which also swaps the other vectors
This is obviously very appalling, trivial to abuse in horrible ways, but arguably much shorter than the pair of iterators and probably similar in performance. And it actually works.
Note that swap() could be implemented inside ValueVectorSingleton and the one injected in the std namespace would just call it. That would avoid having to make vv and kv public. Also, the addresses of a and b could further be checked to make sure they are inside kv and not some other vector. Also, this is limited to sorting by values of only one vector (can't sort by corresponding values in both vectors at the same time). And the template parameters could be simply KeyType and ValueType, this was written in a hurry.
Here is a solution I once used to sort an array together with an array of indices (--maybe it is from somewhere over here?):
template <class iterator>
class IndexComparison
{
public:
IndexComparison (iterator const& _begin, iterator const& _end) :
begin (_begin),
end (_end)
{}
bool operator()(size_t a, size_t b) const
{
return *std::next(begin,a) < *std::next(begin,b);
}
private:
const iterator begin;
const iterator end;
};
Usage:
std::vector<int> values{5,2,5,1,9};
std::vector<size_t> indices(values.size());
std::iota(indices.begin(),indices.end(),0);
std::sort(indices.begin(),indices.end()
, IndexComparison<decltype(values.cbegin())>(values.cbegin(),values.cend()));
Afterwards, the integers in vector indices are permuted such that they correspond to increasing values in the vector values. It is easy to extend this from less-comparison to general comparison functions.
Next, in order to sort also the values, you can do another
std::sort(values.begin(),values.end());
using the same comparison function. This is the solution for the lazy ones. Of course, you can alternatively also use the sorted indices according to
auto temp=values;
for(size_t i=0;i<indices.size();++i)
{
values[i]=temp[indices[i]];
}
DEMO
EDIT: I just realized that the above sorts into the opposite direction than the one you were asking for.
Why does stable_sort need a copy constructor? (swap should suffice, right?)
Or rather, how do I stable_sort a range without copying any elements?
#include <algorithm>
class Person
{
Person(Person const &); // Disable copying
public:
Person() : age(0) { }
int age;
void swap(Person &other) { using std::swap; swap(this->age, other.age); }
friend void swap(Person &a, Person &b) { a.swap(b); }
bool operator <(Person const &other) const { return this->age < other.age; }
};
int main()
{
static size_t const n = 10;
Person people[n];
std::stable_sort(people, people + n);
}
Expanding upon the discussion in the OP, and because I found it interesting, here's a solution which uses only swap to sort the original vector (by using a pointer wrapper to sort indices).
Edit: this is the solution v2, which swaps in-place.
Edit (by OP): An STL-friendly version which doesn't require C++11.
template<class Pred>
struct swapping_stable_sort_pred
{
Pred pred;
swapping_stable_sort_pred(Pred const &pred) : pred(pred) { }
template<class It>
bool operator()(
std::pair<It, typename std::iterator_traits<It>::difference_type> const &a,
std::pair<It, typename std::iterator_traits<It>::difference_type> const &b) const
{
bool less = this->pred(*a.first, *b.first);
if (!less)
{
bool const greater = this->pred(*b.first, *a.first);
if (!greater) { less = a.second < b.second; }
}
return less;
}
};
template<class It, class Pred>
void swapping_stable_sort(It const begin, It const end, Pred const pred)
{
typedef std::pair<It, typename std::iterator_traits<It>::difference_type> Pair;
std::vector<Pair> vp;
vp.reserve(static_cast<size_t>(std::distance(begin, end)));
for (It it = begin; it != end; ++it)
{ vp.push_back(std::make_pair(it, std::distance(begin, it))); }
std::sort(vp.begin(), vp.end(), swapping_stable_sort_pred<Pred>(pred));
std::vector<Pair *> vip(vp.size());
for (size_t i = 0; i < vp.size(); i++)
{ vip[static_cast<size_t>(vp[i].second)] = &vp[i]; }
for (size_t i = 0; i + 1 < vp.size(); i++)
{
typename std::iterator_traits<It>::difference_type &j = vp[i].second;
using std::swap;
swap(*(begin + static_cast<ptrdiff_t>(i)), *(begin + j));
swap(j, vip[i]->second);
swap(vip[j], vip[vip[j]->second]);
}
}
template<class It>
void swapping_stable_sort(It const begin, It const end)
{ return swapping_stable_sort(begin, end, std::less<typename std::iterator_traits<It>::value_type>()); }
I don't own a copy of the standard. For what it's worth, this is the wording from a freely available 2010 draft:
25.4.1.2 stable_sort
[...]
Requires: The type of *first shall satisfy the Swappable requirements (Table 37), the MoveConstructible
requirements (Table 33), and the the MoveAssignable requirements (Table 35).
Testing with the latest Visual C++, it does allow sorting when a move constructor is defined but the copy constructor is private.
So to answer your question: you're out of luck. Use something other than std::stable_sort or use a wrapper class.
I'm working on a project for school and need to sort some data. I've been given a vector of objects and I have to sort the objects (either in place or using an index) based on one of their properties. There are several different objects and several different properties that could it be sorted by. What's the best way to go about doing this?
Use std::sort and a functor. e.g:
struct SortByX
{
bool operator() const (MyClass const & L, MyClass const & R) { return L.x < R.x; }
};
std::sort(vec.begin(), vec.end(), SortByX());
The functor's operator() should return true if L is less than R for the sort order you desire.
There are several different objects and several different properties that could it be sorted by.
While the solution Erik posted is correct, this statement leads me to think that it's impractical at best if you are in fact planning to sort by multiple public data members of multiple classes in multiple ways in the same program, as each sorting method will require its own functor type.
I recommend the following abstraction:
#include <functional>
template<typename C, typename M, template<typename> class Pred = std::less>
struct member_comparer : std::binary_function<C, C, bool> {
explicit member_comparer(M C::*ptr) : ptr_{ptr} { }
bool operator ()(C const& lhs, C const& rhs) const {
return Pred<M>{}(lhs.*ptr_, rhs.*ptr_);
}
private:
M C::*ptr_;
};
template<template<typename> class Pred = std::less, typename C, typename M>
member_comparer<C, M, Pred> make_member_comparer(M C::*ptr) {
return member_comparer<C, M, Pred>{ptr};
}
Usage would look like:
#include <algorithm>
#include <string>
#include <vector>
struct MyClass {
int i;
std::string s;
MyClass(int i_, std::string const& s_) : i{i_}, s{s_} { }
};
int main() {
std::vector<MyClass> vec;
vec.emplace_back(2, "two");
vec.emplace_back(8, "eight");
// sort by i, ascending
std::sort(vec.begin(), vec.end(), make_member_comparer(&MyClass::i));
// sort by s, ascending
std::sort(vec.begin(), vec.end(), make_member_comparer(&MyClass::s));
// sort by s, descending
std::sort(vec.begin(), vec.end(), make_member_comparer<std::greater>(&MyClass::s));
}
This will work for any type with public data members, and will save a lot of typing if you need to sort your classes more than a couple of different ways.
Here is a variation that works with public member functions instead of public data members:
#include <functional>
template<typename C, typename M, template<typename> class Pred = std::less>
struct method_comparer : std::binary_function<C, C, bool> {
explicit method_comparer(M (C::*ptr)() const) : ptr_{ptr} { }
bool operator ()(C const& lhs, C const& rhs) const {
return Pred<M>{}((lhs.*ptr_)(), (rhs.*ptr_)());
}
private:
M (C::*ptr_)() const;
};
template<template<typename> class Pred = std::less, typename C, typename M>
method_comparer<C, M, Pred> make_method_comparer(M (C::*ptr)() const) {
return method_comparer<C, M, Pred>{ptr};
}
With usage like:
#include <algorithm>
#include <string>
#include <vector>
class MyClass {
int i_;
std::string s_;
public:
MyClass(int i, std::string const& s) : i_{i}, s_{s} { }
int i() const { return i_; }
std::string const& s() const { return s_; }
};
int main() {
std::vector<MyClass> vec;
vec.emplace_back(2, "two");
vec.emplace_back(8, "eight");
// sort by i(), ascending
std::sort(vec.begin(), vec.end(), make_method_comparer(&MyClass::i));
// sort by s(), ascending
std::sort(vec.begin(), vec.end(), make_method_comparer(&MyClass::s));
// sort by s(), descending
std::sort(vec.begin(), vec.end(), make_method_comparer<std::greater>(&MyClass::s));
}
Here is my version of the answer, just use a lambda function! It works, it uses way less code, and in my opinion it's elegant!
#include <algorithm>
#include <vector>
#include <string>
struct MyClass
{
int i;
std::string s;
MyClass(int i_, std::string const& s_) : i(i_), s(s_) { }
};
int main()
{
std::vector<MyClass> vec;
vec.push_back(MyClass(2, "two"));
vec.push_back(MyClass(8, "eight"));
// sort by i, ascending
std::sort(vec.begin(), vec.end(), [](MyClass a, MyClass b){ return a.i < b.i; });
// sort by s, ascending
std::sort(vec.begin(), vec.end(), [](MyClass a, MyClass b){ return a.s < b.s; });
// sort by s, descending
std::sort(vec.begin(), vec.end(), [](MyClass a, MyClass b){ return a.s > b.s; });
}
sort(v.begin(), v.end(), [](const Car* lhs, const Car* rhs) {
return lhs->getPassengers() < rhs->getPassengers();
});
EDIT: replacing with lambda_compare, because I'm a masochist:
You can also just create a helper that lets you specify which value to use via a lambda expression:
template <class F> class lambda_compare
{
public:
lambda_compare(F f_): f(f_) { }
template <class T> bool operator()(const T &lhs, const T &rhs) const
{ return f(lhs)<f(rhs); }
private:
F f;
};
template <class F> lambda_compare<F> make_lambda_compare(F f)
{ return f; }
...
std::sort(vec.begin(), vec.end(), make_lambda_compare([](const foo &value) { return value.member; }));
I need to find the indexes in the vector based on several boolean predicates.
ex:
vector<float> v;
vector<int> idx;
idx=where( bool_func1(v), bool_func2(v), ... );
What is the way to declare **where** function, in order to use the several user defined boolean functions over the vector?
thanks
Arman.
Edit after one week
I did some complex solutions with templates. But in reality one can use already predefined valarray for my tasks. Here is the code snippet maybe one can find it useful:
double dr=Rc/(double)Nbins, r;
sigma.resize(Nbins);
rr=sigma;
valarray<double> vz(&data.vz[0], data.vz.size());
double mvel=vz.sum()/(double)vz.size();
for(size_t i=0l;i<Nbins;i++)
{
r=dr*i;
valarray<bool> ids = (dist < r+dr) && (dist > r);//The magic valarray<bool>
if(ids.max())
{
valarray<double> d=vz[ids];//we can use indirect operation.
d-=mvel;
d=pow(d,2.0);
sigma[i]= sqrt(d.sum()/(double)d.size());
rr[i]=r;
cout<<i<<") "<<r<<" "<<sigma[i]<<endl;
}
}
Make your bool_xxx functions actually functors of a specific kind of type (tag dispatching would be enough). Then override || and && for them such that these operators return a bool_and, or bool_or. Then you can use your bool_ predicates like so:
std::find_if(vect.begin(), vect.end(), bool_x1() || bool_x2() && (bool_x3() || bool_x4() && bool_x5()));
If you're tempted to write a "where" function then you apparently want to do this more than once with a different set of bool_xxx functions. Even if you know that you want a certain type of composition now, you may as well make it as universal as possible. This is how I'd do it.
Edit:
Based on this comment: #Jerry: For example I need to know: id=where(v < 10.0 && v>1.0); and somewhere later I would like to know: id=where(v < fun(v)); you may be better off with boost::lambda:
namespace l = boost::lambda;
std::find_if(vect.begin(), vect.end(), l::_1 < 10.0 && l::_1 > 1.0);
std::find_if(vect.begin(), vect.end(), l::_1 < l::bind(fun, l::_1));
Or, if you hate lambda or aren't allowed to use it...or just want a very slightly nicer syntax (but inability to use functions directly) then just make your own placeholder type and override it to return bool_xxx functors on operators <, >, etc...
Edit2: Here's an untested where that returns a vector of iterators to all objects matching:
template < typename ForwardIter, typename Predicate >
std::vector<ForwardIter> where(ForwardIter beg, ForwardIter end, Predicate pred)
{
ForwardIter fit = std::find_if(beg,end,pred);
if (fit == end) return std::vector<ForwardIter>();
ForwardIter nit = fit; ++nit;
std::vector<ForwardIter> collection = where(nit,end,pred);
collection.push_front(fit);
return collection;
}
It's recursive and could be slow on some implementations but there's one way to do it.
You could use a predicated version of transform, if there were one. There's not one, but it is very easy to write:
template<class InputIterator, class OutputIterator, class UnaryFunction, class Predicate>
OutputIterator transform_if(InputIterator first,
InputIterator last,
OutputIterator result,
UnaryFunction f,
Predicate pred)
{
for (; first != last; ++first)
{
if( pred(*first) )
*result++ = f(*first);
}
return result;
}
Then you would need a way to make a composite of multiple predicates, so that you could express something like find_if( begin, end, condition1 && condition2 ). This, again, is easy to write:
template<typename LHS, typename RHS> struct binary_composite : public std::unary_function<Gizmo, bool>
{
binary_composite(const LHS& lhs, const RHS& rhs) : lhs_(&lhs), rhs_(&rhs) {};
bool operator()(const Gizmo& g) const
{
return lhs_->operator()(g) && rhs_->operator()(g);
}
private:
const LHS* lhs_;
const RHS* rhs_;
};
Finally you need a gizmo that transform_if uses to convert an object reference to an object pointer. Surprise, surprise, easy to write...
template<typename Obj> struct get_ptr : public std::unary_function<Obj, Obj*>
{
Obj* operator()(Obj& rhs) const { return &rhs; }
};
Let's put this all together with a concrete example. Gizmo below is the object that you have a collection of. We have 2 predicates find_letter and find_value that we want to search for matches to in our main vector. transform_if is the predicated version of transform, get_ptr converts an object reference to a pointer, and binary_composite strings together the two composites.
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <functional>
#include <vector>
using namespace std;
struct Gizmo
{
string name_;
int value_;
};
struct find_letter : public std::unary_function<Gizmo, bool>
{
find_letter(char c) : c_(c) {}
bool operator()(const Gizmo& rhs) const { return rhs.name_[0] == c_; }
private:
char c_;
};
struct find_value : public std::unary_function<Gizmo, int>
{
find_value(int v) : v_(v) {};
bool operator()(const Gizmo& rhs) const { return rhs.value_ == v_; }
private:
int v_;
};
template<typename LHS, typename RHS> struct binary_composite : public std::unary_function<Gizmo, bool>
{
binary_composite(const LHS& lhs, const RHS& rhs) : lhs_(&lhs), rhs_(&rhs) {};
bool operator()(const Gizmo& g) const
{
return lhs_->operator()(g) && rhs_->operator()(g);
}
private:
const LHS* lhs_;
const RHS* rhs_;
};
template<typename LHS, typename RHS> binary_composite<LHS,RHS> make_binary_composite(const LHS& lhs, const RHS& rhs)
{
return binary_composite<LHS, RHS>(lhs, rhs);
}
template<class InputIterator, class OutputIterator, class UnaryFunction, class Predicate>
OutputIterator transform_if(InputIterator first,
InputIterator last,
OutputIterator result,
UnaryFunction f,
Predicate pred)
{
for (; first != last; ++first)
{
if( pred(*first) )
*result++ = f(*first);
}
return result;
}
template<typename Obj> struct get_ptr : public std::unary_function<Obj, Obj*>
{
Obj* operator()(Obj& rhs) const { return &rhs; }
};
int main()
{
typedef vector<Gizmo> Gizmos;
Gizmos gizmos;
// ... fill the gizmo vector
typedef vector<Gizmo*> Found;
Found found;
transform_if(gizmos.begin(), gizmos.end(), back_inserter(found), get_ptr<Gizmo>(), binary_composite<find_value,find_letter>(find_value(42), find_letter('a')));
return 0;
}
EDIT:
Based on sbi's iterative approach, here's a predicated version of copy, which is more in line with the general STL paradigm, and can be used with back_insert_iterator to accomplish what's wanted in this case. It will give you a vector of object, not iterators or indexes, so the transform_if I posted above is still better for this use than copy_if. But here it is...
template<class InputIterator, class OutputIterator, class Predicate>
OutputIterator copy_if(InputIterator first,
InputIterator last,
OutputIterator result,
Predicate pred)
{
for (; first != last; ++first)
{
if( pred(*first) )
*result++ = *first;
}
return result;
}
This seems like a problem that could much easier be solved in an declarative language like Prolog. I gave it a try in C++ anyway:
typedef float type;
typedef bool (*check)(type);
std::vector<int> where(const std::vector<type>& vec,
const std::vector<check>& checks)
{
std::vector<int> ret;
for (int i = 0; i < vec.size(); i++)
{
bool allGood = true;
for (int j = 0; j < checks.size(); j++)
{
if (!checks[j](vec[i]))
{
allGood = false;
break;
}
}
if (allGood)
ret.push_back(i);
}
return ret;
}
I am not sure which indexes you want. Is this what you are trying to acheive:
//Function pointer declaration
typedef bool (*Predicate)(const std::vector<float>& v);
//Predicates
bool bool_func1(const std::vector<float>& v)
{
//Implement
return true;
}
bool bool_func2(const std::vector<float>& v)
{
//Implement
return true;
}
std::vector<int> where_func(const std::vector<float>& v,
const std::vector<Predicate>& preds)
{
std::vector<int> idxs;
std::vector<Predicate>::const_iterator iter = preds.begin();
std::vector<Predicate>::const_iterator eiter = preds.end();
for(; iter != eiter; ++iter)
{
if((*iter)(v))
{
idxs.push_back(eiter - iter);
}
}
return idxs;
}
template<typename Vector, typename T> std::vector<int> where(const std::vector<Vector>& vec, T t) {
std::vector<int> results;
for(int i = 0; i < vec.size(); i++) {
if (t(vec[i])
results.push_back(i)
}
return results;
}
Overload for additional function object arguments as you wish. Use:
template<typename T> struct AlwaysAccept {
bool operator()(const T& t) { return true; }
};
std::vector<float> floats;
// insert values into floats here
std::vector<int> results = where(floats, AlwaysAccept<float>());
Noah Robert's solution is nice, but I'm not wholly sure how I could make that work.