2
votes

Comment obtenir les 100 meilleurs noms d'une collection

Je crée un programme où je résume à partir d'un fichier de données. Le fichier de données contient des informations sur les prénoms, etc. Les informations sont les champs du fichier csv. Les champs du fichier de données sont inclus en tant que variables d'instance dans la classe. J'ai créé des méthodes setter et getter pour renvoyer les données d'une personne. J'ai créé des vecteurs pour contenir la collection de variables.

J'ai du mal à comprendre comment créer une liste des 100 prénoms les plus courants de toutes les personnes de la collection. La liste doit être dans l'ordre décroissant d'occurrence.

J'ai pu imprimer tous les noms communs et ses fréquences. Mais je ne peux pas imprimer les 100 noms les plus courants. J'ai trié le vecteur et j'ai obtenu les erreurs suivantes:

  1. la classe std::pair<const std::string, int> n'a pas de membre begin et end

Veuillez m'aider à résoudre ces problèmes. Tout le traitement des données dans le vecteur doit être effectué avec des itérateurs.Je ne sais pas comment résoudre ces problèmes car je suis un débutant.

std::vector<std::string> commonNamesFirst; //vector

for (auto x : census) {
    commonNamesFirst.push_back(x.getFirstName()); //populate vector
}

std::map<std::string, int> frequencies; 

for (auto& x : census) { ++frequencies[x.getFirstName()]; }

for (auto& freq : frequencies) {
    sort(freq.begin(), freq.end(), greater <>()); //error, need to sort in descending order

    cout << freq.first << ": " << freq.second << endl; //print the 100 common names in descending order
}

c++

6 commentaires

std::map est trié automatiquement, vous n'avez pas besoin (et vous ne pouvez pas) le trier vous-même. Si vous souhaitez trier les données dans une carte, vous devez d'abord les copier dans un vecteur, puis trier le vecteur.


Hors sujet, mais notez qu'il existe d'autres moyens de résoudre ce problème, notamment en utilisant un min-heap. Si le nombre total d'éléments était énorme et que vous ne voulez que les 100 premiers, vous utiliseriez / devriez utiliser un minheap.


@ChandMoon Copiez les données cartographiques dans un vecteur, triez le vecteur, imprimez les 100 premières entrées du vecteur. Vous sentez-vous capable de faire ces choses?


@ChandMoon Vous devriez essayer, c'est ainsi que vous apprenez. Si vous êtes complètement bloqué, il serait peut-être préférable de trouver quelqu'un à qui parler en personne, un enseignant ou un autre élève. Malheureusement, ce n'est pas un site sur lequel nous écrirons votre code pour vous.


@ChandMoon - Si vous êtes débutant, pourquoi ne pas faire une expérience? Écrivez une boucle qui imprime chacune des entrées de la carte, puis déterminez quoi faire avec les données que vous voyez dans la sortie.


Commencez par ce std::vector<std::string, int> sortedFrequencies; C'est le vecteur dans lequel vous allez copier les données cartographiques, puis les trier.


4 Réponses :


0
votes

L'erreur que vous obtenez, dit tout. Vous essayez de trier individuellement std::pair . Je pense que le meilleur moyen serait de transform votre carte en un std::vector de paires, puis de sort ce vecteur. Ensuite, parcourez les 100 premiers éléments dans une boucle et imprimez les résultats.


0 commentaires

3
votes
std::vector<std::pair<std::string, int>> vfrequencies{
     frequencies.begin(),
     frequencies.end()
};

0 commentaires

1
votes

Vous ne pouvez pas (re) trier std::map , vous pouvez copier les fréquences dans vector ou std::multimap comme intermédiaire:

std::map<std::string, int> frequencies;
for (auto& x : census) { ++frequencies[x.getFirstName()]; }

std::vector<std::pair<std::string, int>> freqs{frequencies.begin(), frequencies.end()};

std::partial_sort(freqs.begin(), freqs.begin() + 100, freqs.end(),
                  [](const auto& lhs, const auto& rhs){ return lhs.second > rhs.second; });
for (std::size_t i = 0; i != 100; ++i)
{
    std::cout << freqs[i].second << ":" << freqs[i] << std::endl;
}


0 commentaires

1
votes

En vous appuyant sur la réponse de @ MichaÅ ‚Kaczorowski, vous essayez de trier les valeurs de chaque paire au lieu des paires de la carte. Cependant, comme Sam l'a mentionné, vous ne pouvez pas trier un std::map (l'implémentation interne stocke les choses triées par la valeur de clé, ou le nom dans ce cas). Vous devrez extraire les valeurs de la carte et les trier ensuite, ou utiliser une file d'attente prioritaire et un tri en tas (facteur constant plus rapide), ou une file d'attente monotone (temps linéaire mais plus difficile à implémenter). Voici un exemple d'implémentation de Heapsort:

vector<string> commonNamesFirst; //vector

for (auto x : census) {
    commonNamesFirst.push_back(x.getFirstName()); //populate vector
}

std::map<std::string, int> frequencies; 

for (auto& x : census) { ++frequencies[x.getFirstName()]; }

std::priority_queue<pair<int, std::string> > top_names;  // put the frequency before the name to take advantage of default pair compare

for (auto& freq : frequencies) top_names.push(std::make_pair(freq.second, freq.first));
for (int i=0; i<100; ++i)
{
    outputFile << top_names.top().second << ": " << top_names.top().first << endl; //print the 100 common names in descending order
    top_names.pop();
}


0 commentaires