[C++] partial_sort_copy et indices

Bonjour,

j'ai un vecteur de la STL
je veux savoir par exemple quels sont les 10 plus grands éléments et aussi savoir leur indice dans le vecteur

partial_sort_copy de la STL peut récupérer les 10 plus grandes valeurs mais comment récupérer les indices de ces valeurs dans mon vecteur d'origine ?

merci
++
Configuration: Linux Fedora
Firefox 2.0.0.5

3 réponses

  1. Modérateur
    Voici une façon de faire :
    #include <vector>
    #include <map>
    #include <iostream>
    
    // On ne conserve que les n premiers éléments en accord avec la relation d'ordre choisie
    template <typename T,typename Tsort>
    void find_n_best_elements(
        const std::vector<T> & v,
        unsigned n,
        std::map<T,std::size_t,Tsort> & map_n_best_elements
    ){
        const std::size_t vsize = v.size();
        for(std::size_t i=0;i<vsize;++i){
            map_n_best_elements[v[i]] = i;
            if(map_n_best_elements.size() > n){
                // On vire le n+1 ieme élément car on a déjà n éléments meilleurs
                map_n_best_elements.erase(map_n_best_elements.rbegin()->first);
            }
        }
    }
    
    int main(){
        // Construire le vecteur de départ
        std::vector<int> v;
        v.push_back(1);
        v.push_back(4);
        v.push_back(2);
        v.push_back(8);
        v.push_back(5);
        v.push_back(3);
        v.push_back(7);
    
        // Afficher le vecteur
        const std::size_t vsize = v.size();
        for(std::size_t i=0;i<vsize;++i){
            std::cout << "v[" << i << "]\t" << v[i] << std::endl;
        }
    
        // Chercher les n=3 plus grands entiers
        // - les valeurs sont des ici int
        // - les index sont toujours des std::size_t
        // - la relation d'ordre est std::greater (un élément plus grand est meilleur qu'un élément plus petit)
        typedef std::map<int,std::size_t,std::greater<int> > my_map_t;
        my_map_t map_3_biggest_int;
        find_n_best_elements(v,3,map_3_biggest_int);
    
        // Afficher le résultat
        my_map_t::const_iterator
            mit (map_3_biggest_int.begin()),
            mend(map_3_biggest_int.end());
        for(;mit!=mend;++mit){
            std::cout << "valeur = "  << mit->first << "\tindex = "
                << mit->second << std::endl;
        }
        return 0;
    }

    Ce qui donne ;
    v[0]    1
    v[1]    4
    v[2]    2
    v[3]    8
    v[4]    5
    v[5]    3
    v[6]    7
    valeur = 8      index = 3
    valeur = 7      index = 6
    valeur = 5      index = 4
    

    Tu noteras que si tu cherches les n plus petits éléments il te suffit de changer std::greater par std::less (qui est la relation d'ordre par défaut dans une map).
    ....
        typedef std::map<int,std::size_t,std::less<int> > my_map_t;
        // ou directement : typedef std::map<int,std::size_t > my_map_t;
    ....
    

    donne :
    v[0]    1
    v[1]    4
    v[2]    2
    v[3]    8
    v[4]    5
    v[5]    3
    v[6]    7
    valeur = 1      index = 0
    valeur = 2      index = 2
    valeur = 3      index = 5
    

    Tu peux aussi définir ton propre foncteur si tu souhaites utiliser une autre relation d'ordre que std::less ou std::greater
    https://cpp.developpez.com/faq/cpp/?page=La-STL#STL_functor

    Bonne chance
    0
    1. merci pour ta réponse détaillée et rapide !

      et si je veux récupérer les indices des valeurs qui sont au-dessus d'un seuil ?
      il y a une fonction de la STL pour faire ça ?

      merci encore
      ++
      0
      1. Modérateur
        Il faut lire la doc :)
        https://community.hpe.com/t5/custom/page/page-id/HPPSocialUserSignonPage?redirectreason=permissiondenied&referer=https%3A%2F%2Fcommunity.hpe.com%2Ft5%2FServers-Systems-The-Right%2FSGI-com-Tech-Archive-Resources-now-retired%2Fba-p%2F6992583

        Cf les fonctions upper_bound et lower_bound. Contrairement au find la clé recherchée n'a pas besoin d'être dans le container (ce qui revient à rechercher un seuil) (find() renvoie end() si la clé n'existe pas).
        #include <iostream>
        #include <set>
        
        int main(){
            std::set<int> s;
            s.insert(5);
            s.insert(3);
            s.insert(1);
            s.insert(7);
            s.insert(2);
            s.insert(8);
        
            // Parcourir l'ensemble
            std::cout << "[begin...end[: ";
            for(std::set<int>::const_iterator it=s.begin();it!=s.end();++it){
                std::cout << *it << ' ';
            }
            std::cout << std::endl;
        
            const int bound = 3;
            std::set<int>::const_iterator
                it_ub = s.upper_bound(bound),
                it_lb = s.lower_bound(bound),
                it_end = s.end();
        
            std::cout << "LB(" << bound << ") = "  << *it_lb << std::endl
                      << "UB(" << bound << ") = " << *it_ub  << std::endl;
        
            // Parcourir de begin à UB (exclue) (ie jusqu'à LB comprise):
            std::cout << "[begin...UB[: ";
            for(std::set<int>::const_iterator it=s.begin();it!=it_ub;++it){
                std::cout << *it << ' ';
            }
            std::cout << std::endl;
        
            // Parcourir de UB (comprise) à end :
            std::cout << "[UB...end[: ";
            for(std::set<int>::const_iterator it=it_ub;it!=it_end;++it){
                std::cout << *it << ' ';
            }
            std::cout << std::endl;
        
            return 0;
        }
        

        ce qui donne :
        [begin...end[: 1 2 3 5 7 8
        LB(3) = 3
        UB(3) = 5
        [begin...UB[: 1 2 3
        [UB...end[: 5 7 8

        Bonne chance
        0