Does anyone know how to do this?

I attached a program that collects all the command line arguments into a map container noting how many times each command line argument occurs. Now I want to sort this map of information by loading a vector with iterators that point to each map element and sort the iterators. I'm just wondering, what is the best way to do this. My method works but I'm wondering is it the proper way to do it?.

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <iterator>
#include <algorithm>

struct mys
{
    unsigned long a;
};

std::ostream& operator <<(std::ostream & out, const struct mys & m)
{
    return out << m.a;
}

std::ostream& operator <<(std::ostream & out, const std::pair<const std::string, struct mys> & p)
{
    return out << p.first << " " << p.second;
}

std::ostream& operator <<(std::ostream & out, const std::map<std::string, struct mys>::const_iterator & i)
{
    return out << *i;
}

bool compare_iterator(const std::map<std::string, struct mys>::const_iterator & a, const std::map<std::string, struct mys>::const_iterator & b)
{
    return a->second.a > b->second.a || ( a->second.a == b->second.a && a->first > b->first );
}

int main(int argc, char** argv)
{
    std::map<std::string, struct mys> the_words;
    std::vector<std::map<std::string, struct mys>::const_iterator > the_vec;

    for (std::map<std::string, unsigned long>::size_type i = 1; i < argc; ++i)
        the_words[argv[i]].a++;

    std::map<std::string, struct mys>::const_iterator begin = the_words.begin();
    std::map<std::string, struct mys>::const_iterator end = the_words.end();

    while ( begin != end )
    {
        the_vec.push_back(begin);
        ++begin;
    }

    sort(the_vec.begin(), the_vec.end(), compare_iterator);

    copy(the_vec.begin(), the_vec.end(), std::ostream_iterator<std::map<std::string, struct mys>::const_iterator >(std::cout, "\n"));

    return 0;
}

Edited 4 Years Ago by gerard4143

Maybe a map is not the best way to go about that. Another way is to create a structure that contains a string for the argv entry and int for counter, then create a vector of those structures. After that, just call std::sort() to sort any way you want it.

@ Ancient D.
Yes I agree with your point but I'm interested in sorting a standard container called say 'first_container' via another container which has iterators pointing to the first container. Hope that makes sense.

I'm interested in sorting a standard container called say 'first_container' via another container which has iterators pointing to the first container.

An indirect sort is useful in many situations

  • a sequence is immutable, but we want a sorted view of the sequence
  • we want to access the sequence in two ways - in the original order and in the sorted order
  • a sequence contains objects which are expensive to move around, and we want a sorted view

The options available are:

  • indirect sort with reference_wrappers
  • indirect sort with iterators
  • indirect sort with pointers

The code using reference_wrappers tends to be cleaner than the code using either pointers or iterators.

const std::list<int> seq = { 42, 24, 75, 65, 42, 53, 65, 75, 74, 63, 46, 52, 35 } ;
for( int v : seq ) std::cout << v << ' ' ; std::cout << '\n' ;
// 42 24 75 65 42 53 65 75 74 63 46 52 35

// indirect sort with reference wrappers
std::vector< std::reference_wrapper<const int> > ref_wrappers( seq.begin(), seq.end() ) ;
std::sort( ref_wrappers.begin(), ref_wrappers.end() ) ;
for( const auto& rw : ref_wrappers ) std::cout << rw << ' ' ; std::cout << '\n' ;
// 24 35 42 42 46 52 53 63 65 65 74 75 75

// indirect sort with iterators
using iterator = std::list<int>::const_iterator ;
std::vector<iterator> iters ;
for( auto iter = seq.begin() ; iter != seq.end() ; ++iter ) iters.push_back(iter) ;
std::sort( iters.begin(), iters.end(), [] ( iterator a, iterator b ) { return *a < *b ; } ) ;
for( iterator iter : iters ) std::cout << *iter << ' ' ; std::cout << '\n' ;
// 24 35 42 42 46 52 53 63 65 65 74 75 75

// indirect sort with pointers
using pointer = std::list<int>::const_pointer ;
std::vector<pointer> pointers ;
for( const int& v : seq ) pointers.push_back( &v ) ;
std::sort( pointers.begin(), pointers.end(), [] ( pointer a, pointer b ) { return *a < *b ; } ) ;
for( pointer ptr : pointers ) std::cout << *ptr << ' ' ; std::cout << '\n' ;
// 24 35 42 42 46 52 53 63 65 65 74 75 75
Comments
Nice detailed reply - Thanks
This question has already been answered. Start a new discussion instead.