2012-06-15 6 views
5

Quiero obtener los elementos ordenados por el número de su aparición. Esto es lo que he llegado con (mHeights es un std :: conjunto múltiple):Cómo ordenar un multiset a un contenedor por el número de ocurrencias de elementos

namespace{ 
    template<class U,class T> 
    class HistPair{ 
    public: 
     HistPair(U count,T const& el):mEl(el),mNumber(count){  
     } 
     T const& getElement()const{return mEl;} 

     U getCount()const{return mNumber;} 
    private: 
     T mEl; 
     U mNumber; 
    }; 

    template<class U,class T> 
    bool operator <(HistPair<U,T> const& left,HistPair<U,T> const& right){ 
    return left.getCount()< right.getCount(); 
    } 
} 

std::vector<HistPair<int,double> > calcFrequentHeights(){ 
    typedef HistPair<int,double> HeightEl; 
    typedef std::vector<HistPair<int,double> > Histogram; 
    std::set<double> unique(mHeights.begin(),mHeights.end()); 
    Histogram res; 
    boostForeach(double el, unique) { 
    res.push_back(HeightEl(el,mHeights.count(el)));  
    } 
    std::sort(res.begin(),res.end()); 
    std::reverse(res.begin(),res.end()); 
    return res; 
} 

Así que primero tomo todos los elementos singulares del conjunto múltiple, luego les cuento y clasificarlos en un nuevo contenedor (I necesito los conteos así que uso un mapa). Esto parece bastante complicado para una tarea tan fácil. Además del HistPair, que también se usa en otros lugares, ¿no hay algún algoritmo stl que simplifique esta tarea, p. usando equal_range o sth. igual.

Editar: Necesito el número de ocurrencias, así, lo siento, se olvidó de que

+1

parece bastante conciso para mí . No puedo imaginar que pienses más de una o dos líneas en tu rutina de creación de histogramas. Una alternativa podría ser utilizar un 'std :: map ' en lugar de 'std :: multiset ' y calcular los tamaños de los contenedores al insertar elementos, pero no cambiará mucho. – Rook

+0

@nims: Eso es lo que estoy haciendo o no te he entendido bien. Necesito el recuento y el elemento – Martin

+0

@Martin mi mal, lo pasé por alto. – nims

Respuesta

6

Este fragmento de código hace lo que quiere, mediante la combinación de un std::set, un lambda y std::multiset::count:

#include <iostream> 
#include <set> 
#include <vector> 
#include <algorithm> 

int main() { 
    std::multiset<int> st; 
    st.insert(12); 
    st.insert(12); 
    st.insert(12); 
    st.insert(145); 
    st.insert(145); 
    st.insert(1); 
    st.insert(2); 

    std::set<int> my_set(st.begin(), st.end()); 
    std::vector<int> my_vec(my_set.begin(), my_set.end()); 
    std::sort(my_vec.begin(), my_vec.end(), 
     [&](const int &i1, const int &i2) { 
      return st.count(i1) < st.count(i2); 
     } 
    ); 

    for(auto i : my_vec) { 
     std::cout << i << " "; 
    } 
    std::cout << std::endl; 
} 

Usted podría querer invertir el vector. Esto da salida:

1 2 145 12 

Editar: Teniendo en cuenta que también es necesario el recuento de elementos, esto lo hará:

#include <iostream> 
#include <set> 
#include <vector> 
#include <algorithm> 

int main() { 
    typedef std::vector<std::pair<int, int>> MyVector; 
    std::multiset<int> st; 
    st.insert(12); 
    st.insert(12); 
    st.insert(12); 
    st.insert(145); 
    st.insert(145); 
    st.insert(1); 
    st.insert(2); 

    std::set<int> my_set(st.begin(), st.end()); 
    MyVector my_vec; 
    my_vec.reserve(my_set.size()); 

    for(auto i : my_set) 
     my_vec.emplace_back(i, st.count(i)); 

    std::sort(my_vec.begin(), my_vec.end(), 
     [&](const MyVector::value_type &i1, const MyVector::value_type &i2) { 
      return i1.second < i2.second; 
     } 
    ); 

    for(const auto &i : my_vec) 
     std::cout << i.first << " -> " << i.second << std::endl; 
} 

que da salida:

1 -> 1 
2 -> 1 
145 -> 2 
12 -> 3 
+0

Gracias. Las lambdas son útiles ;-) Sin embargo, olvidé mencionar que también necesito los conteos, pero esto no debería ser difícil de integrar en tu solución. – Martin

+0

Ahí tienes, editó mi respuesta. – mfontanini

+0

¡Gracias de nuevo! – Martin

Cuestiones relacionadas