Sorting by a transformation function
Hi,
I would like to sort a vector ordered by the return value of a unary
transformation function, op. The elements of the vector do not have a
copy constructor. The transformation function is expensive and show be
called exactly once for each element of the vector. I have a solution,
included below. I want to know if this operation is possible using
ether standard functions or using boost, and whether my solution could
be improved at all. For bonus points, I'd like to include an optional
binary predicate as a fourth parameter that can be passed to
std::sort.
Cheers,
Shaun
#include <algorithm>
#include <cassert>
#include <iterator>
#include <utility>
#include <vector>
/** Sorts the elements in the range [first,last) ordered by the value
* returned by the unary function op, which is called once for each
* element in the range [first,last). The copy constructor of the
* value_type of It is not used.
* @author Shaun Jackman <sjackman@gmail.com>
*/
template <class It, class Op>
void sort_by_transform(It first, It last, Op op)
{
typedef typename std::iterator_traits<It>::difference_type
size_type;
typedef typename Op::result_type key_type;
size_type n = last - first;
std::vector< std::pair<key_type, size_type> > keys;
keys.reserve(n);
for (It it = first; it != last; ++it)
keys.push_back(make_pair(op(*it), it - first));
sort(keys.begin(), keys.end());
// Initialize the permutation matrix P to the identity matrix.
std::vector<size_type> row(n), column(n);
for (size_type i = 0; i < n; i++)
row[i] = column[i] = i;
// Find the row-interchanging elementary matrices of P, and apply
// them to the vector [first,last).
for (size_type i = 0; i < n; i++) {
// The elements [0,i) are in their correct positions.
size_type j = column[keys[i].second];
if (i == j)
continue;
assert(i < j);
swap(first[i], first[j]);
// The elements [0,i] are in their correct positions.
// Swap rows i and j of the matrix.
swap(column[row[i]], column[row[j]]);
swap(row[i], row[j]);
assert(row[i] == keys[i].second);
assert(column[row[i]] == row[column[i]]);
assert(column[row[j]] == row[column[j]]);
}
}
#include <fuctional>
#include <iostream>
#include <iterator>
#include <vector>
using namespace std;
int main()
{
vector<string> data;
copy(istream_iterator<string>(cin), istream_iterator<string>(),
back_inserter(data));
sort_by_transform(data.begin(), data.end(),
mem_fun_ref(&string::length));
copy(data.begin(), data.end(),
ostream_iterator<string>(cout, "\n"));
return 0;
}
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]