假設我有一個帶有字串和整數的地圖。讀入文本檔案后,字串包含所有不同的單詞,整數包含每個單詞的頻率。我想在這個文本檔案中顯示 k 個最常用/最不常用的單詞,但我的地圖是通過字串而不是整數進行排序的。這是我的一些代碼:
typedef map<string, int> words;
ifstream file("input.txt");
string word;
while (file >> word)
{
words[word] ;
}
for (WordMap::iterator w = words.begin(); w != words.end(); w )
{
cout << w->first << " = " << w->second << endl;
}
這段代碼正在努力獲取單詞串列和所有單詞的頻率;但是我的輸出是這樣的:
apple = 34
cat = 4
dog = 12
...
如何在此地圖中列印 k 個最頻繁/最不頻繁的單詞?是不是因為我有一個字串作為第一個成員,一個整數作為第二個成員?如果我必須顛倒這兩個的位置,那么我將如何為每個字串添加頻率計數?
uj5u.com熱心網友回復:
您可以創建一個比較函式,使用容器傳遞所有地圖的值并對其進行排序,然后比較最后一個k元素。
bool compare (std::pair<std::string, int>& lhs, std::pair<std::string, int>& rhs)
{
return lhs.second < rhs.second;
}
int main()
{
std::vector<std::pair<std::string, int>> vec;
for(const auto& pr: words)
vec.push_back(make_pair(pr.first, pr.second));
std::sort(vec.begin(), vec.end(), compare);
for(const auto& pr : vec)
{
// print all the values out
std::cout << pr.first << ' ' << pr.second << '\n';
}
}
uj5u.com熱心網友回復:
有一種或多或少的標準方法來計算容器中的東西,然后獲取并顯示它的等級。
對于計數部分,我們可以使用關聯容器,如 astd::map或 a std::unordered_map。在這里,我們將一個“鍵”(在本例中為單詞)與一個計數和一個值(在本例中為特定單詞的計數)相關聯。
幸運的是,基本上選擇這種方法的原因是地圖有一個非常好的索引operator[]。這將查找給定的鍵,如果找到,則回傳對該值的參考。如果未找到,則它將使用該鍵創建一個新條目并回傳對新條目的參考。因此,在這兩種情況下,我們都將獲得對用于計數的值的參考。然后我們可以簡單地寫:
std::unordered_map<char,int> counter{};
counter[word] ;
這看起來非常直觀。
完成此操作后,您已經有了頻率表。要么按鍵(單詞)排序,要么使用 astd::map或 unsorted,但使用 a可以更快地訪問std::unordered_map。
在您的情況下,您只對排序計數感興趣,astd::unordered_map是可取的,因為不需要std::map按其鍵對 a 中的資料進行排序,以后也不使用此排序。
然后,您想根據頻率/計數進行排序。不幸的是,這在地圖上是不可能的。因為映射- 容器系列的主要屬性是它們對鍵的參考,而不是值或計數。
因此,我們需要使用第二個容器,例如 astd::vector等,然后我們可以對std::sort任何給定的謂詞使用它進行排序,或者,我們可以將值復制到一個容器中,例如 astd::multiset對其元素進行隱式排序。因為這只是一個襯里,所以這是推薦的解決方案。
此外,因為要為 std 容器撰寫所有這些長名稱,所以我們使用using關鍵字創建別名。
在我們獲得單詞的排名后,即按計數排序的單詞串列,我們可以使用迭代器和回圈來訪問資料并輸出它們。
我們需要注意帶有排序值的容器包含足夠的值,然后使用簡單的 for 回圈,或者像std::copy_n.
熱值限制?有 3 種可能的解決方案。
- 手寫的大小對比功能
if (elementsToPrint > container.size()) elementsToPrint = container.size() std::min,基本上完成了上述作業。所以,elementsToPrint = std::min(elementsToPrint, container.size());std::clamp. 為此目的而定義的專用函式。請在此處閱讀有關此函式的資訊。結果將是:````elementsToPrint = std::clamp(elementsToPrint,1, container.size());
好的。現在,我們要顯示最低的 k 個等級和最高的 k 個等級。我們可以通過使用指向開始的迭代器來做到這一點,begin()或者,談論結束,std::rbegin()
畢竟,我們現在撰寫超緊湊的代碼,只需幾行代碼即可完成任務:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <utility>
#include <set>
#include <unordered_map>
#include <type_traits>
#include <iomanip>
#include <algorithm>
// ------------------------------------------------------------
// Create aliases. Save typing work and make code more readable
using Pair = std::pair<std::string, unsigned int>;
// Standard approach for counter
using Counter = std::unordered_map<Pair::first_type, Pair::second_type>;
// Sorted values will be stored in a multiset
struct Comp { bool operator ()(const Pair& p1, const Pair& p2) const { return (p1.second == p2.second) ? p1.first<p2.first : p1.second>p2.second; } };
using Rank = std::multiset<Pair, Comp>;
// ------------------------------------------------------------
int main() {
// Open file and check, if it can be opened.
if (std::ifstream inputFileStream{ "input.txt" }; inputFileStream) {
// Definition of our counter
Counter counter;
// Count -------------------------
for (std::string word{}; inputFileStream >> word; counter[word] );
// Sort
Rank rank(counter.begin(), counter.end());
// Output ------------------------
size_t elementsToShow = 3;
// Show 3 biggest counts
auto fromTop = rank.begin();
for (size_t i{}; i < std::clamp(elementsToShow, 1u, rank.size()); i)
std::cout << fromTop->first << '\t' << fromTop ->second << '\n';
// Show 3 smallest counts
auto fromBottom = rank.rbegin();
for (size_t i{}; i < std::clamp(elementsToShow, 1u, rank.size()); i)
std::cout << fromBottom->first << '\t' << fromBottom ->second << '\n';
}
else std::cerr << "\n*** Error. Could not open input file\n\n";
}
Often it is the case that you need to continue to work with the gathered count values. Then the use of std::partial_sort_copy is advisable. Basically we will at this time put all the counts into resulting vectors. Namely top and bottom.
Sorting criteria may also be adjusted in the lambda of the copy function.
Please see one possible solution below:
#include <iostream>
#include <fstream>
#include <string>
#include <utility>
#include <unordered_map>
#include <type_traits>
#include <algorithm>
#include <vector>
// ------------------------------------------------------------
// Create aliases. Save typing work and make code more readable
using Pair = std::pair<std::string, unsigned int>;
// Standard approach for counter
using Counter = std::unordered_map<Pair::first_type, Pair::second_type>;
// Resulting data
using Result = std::vector<Pair>;
// ------------------------------------------------------------
int main() {
// Open file and check, if it can be opened.
if (std::ifstream inputFileStream{ "input.txt" }; inputFileStream) {
// Definition of our counter
Counter counter;
// Count -------------------------
for (std::string word{}; inputFileStream >> word; counter[word] );
// Build result ------------------------
unsigned int three = std::min(3u, counter.size());
Result top(three);
Result bottom(three);
// Get 3 biggest counts
std::partial_sort_copy(counter.begin(), counter.end(), top.begin(), top.end(),
[](const Pair& p1, const Pair& p2) { return p1.second > p2.second; });
// get 3 smallest counts
std::partial_sort_copy(std::next(counter.begin(), counter.size() - three), counter.end(), bottom.begin(), bottom.end(),
[](const Pair& p1, const Pair& p2) { return p1.second > p2.second; });
// Output ------------------------
for (const auto& [word, count] : top) std::cout << word << '\t' << count << '\n';
for (const auto& [word, count] : bottom) std::cout << word << '\t' << count << '\n';
}
else std::cerr << "\n*** Error. Could not open input file\n\n";
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/347786.html
