I have two maps: Pkt_creatingmap and Pkt_arrivalmap. The number of elements in (Pkt_creatingmap) map is much more than the number of elements in (Pkt_arrivalmap) map [i.e.: total number of elements in Pkt_creatingmap about 650000 elements and total number of element in Pkt_arrivalmap about 72000 elements].
I want to compare the key IDs (firsts) in (Pkt_creatingmap) map and (Pkt_arrivalmap) map. If it is equal then subtract the values of key IDs (seconds) and store the result in list (TotalTrafficETED).
I write below code to do this task, However it takes a long time to accomplish (i.e.: it is time consuming). Not all elements in (Pkt_creatingmap) map are needed in this process. The process of subtraction depends only on the elements of (Pkt_arrivalmap) map.
Is there method to reduce the running time? (i.e.: can the iterator of (Pkt_creatingmap) map end at the end location of (Pkt_arrivalmap) map iterator?
Hope my question is clear.
Anyone can help me please or give me another ideal to do this task ..
#include <iostream>
#include <fstream>
#include <string>
#include <stdint.h>
#include <sstream>
#include <cmath>
#include <map>
#include <iterator>
#include <list>
using namespace std;
int main()
{
map<double_t, double_t> Pkt_arrivalmap;
map<double_t, double_t> Pkt_creatingmap;
list<double_t> TotalTrafficETED;
int pos, pos2, pos3;
double_t ArrivingID, CreatingID, ArrivingTime, CreatingTime, Pkt_ETED, TTETED;
string line, search, word1 = "ns", word2 = "Pkt_create", word3 = "Pkt_recv";
ifstream inf;
inf.open("123.txt");
if (inf.is_open()) {
while (getline(inf, line)) {
if (line.find("Pkt_recv") != string::npos) {
pos = line.find(word1);
pos3 = line.find(word3);
line.replace(pos, word1.length(), " "); // to remove "ns"
line.replace(pos3, word3.length(), " "); // to remove "Pkt_recv"
istringstream iss(line);
double_t column1;
//double_t column3;
double_t column2;
iss >> column1 >> column2;
//cout << column1 <<" "<< column2 <<" "<< " "<< endl;
Pkt_arrivalmap[column1] = column2;
}
}
inf.close();
}
else
cout << "Unable to open file inf \n";
for (std::map<double_t, double_t>::iterator it = Pkt_arrivalmap.begin(); it != Pkt_arrivalmap.end(); it++) {
cout << "Arrival info."
<< " " << it->first << " " << it->second << " " << Pkt_arrivalmap.size() << endl;
}
inf.open("123.txt");
if (inf.is_open()) {
while (getline(inf, line)) {
if (line.find("Pkt_create") != string::npos) {
pos = line.find(word1);
pos2 = line.find(word2);
line.replace(pos, word1.length(), " "); // to remove "ns"
line.replace(pos2, word2.length(), " "); // to remove "Pkt_create"
istringstream iss(line);
double_t column1;
//double_t column3;
double_t column2;
iss >> column1 >> column2;
//cout << column1 <<" "<< column2 <<" "<< " "<< endl;
Pkt_creatingmap[column1] = column2;
}
}
inf.close();
}
else
cout << "Unable to open file inf \n";
for (std::map<double_t, double_t>::iterator it = Pkt_creatingmap.begin(); it != Pkt_creatingmap.end(); it++) {
cout << "Creating info."
<< " " << it->first << " " << it->second << " " << Pkt_creatingmap.size() << endl;
}
for (std::map<double_t, double_t>::iterator it = Pkt_arrivalmap.begin(); it != Pkt_arrivalmap.end(); it++) {
ArrivingID = it->first;
ArrivingTime = it->second;
//cout << "Ahmed" <<" "<< ArrivingID <<endl;
for (std::map<double_t, double_t>::iterator it = Pkt_creatingmap.begin(); it != Pkt_creatingmap.end(); it++) {
CreatingID = it->first;
CreatingTime = it->second;
if (ArrivingID == CreatingID) {
Pkt_ETED = (ArrivingTime - CreatingTime) / 1000000000;
TotalTrafficETED.push_back(Pkt_ETED);
Pkt_creatingmap.erase(it->first);
Pkt_arrivalmap.erase(it->first);
cout << "Pkt_ID:" << CreatingID << ","
<< "Pkt_ETED:" << Pkt_ETED << endl;
}
}
}
for (std::list<double_t>::iterator it = TotalTrafficETED.begin(); it != TotalTrafficETED.end(); it++) {
TTETED += *it / TotalTrafficETED.size();
}
cout << "Total Traffic ETED"
<< " " << TTETED << endl;
return 0;
}
If you want to find an element with a given ID in a map, the method map::find is very efficient and proceeds logarithmic in size of the map, because it is a sorted container. In your code, you do two for loop and the complexity is quadratic. Thus, you have to write something like that :
for (std::map<double_t,double_t>::iterator it = Pkt_arrivalmap.begin(); it != Pkt_arrivalmap.end(); it++)
{
ArrivingID =it->first;
ArrivingTime=it->second;
//cout << "Ahmed" <<" "<< ArrivingID <<endl;
map<double_t,double_t>::iterator it2 = Pkt_creatingmap.find(ArrivingID);
if (it2!=Pkt_creatingmap.end()){ // Found equivalent key
CreatingTime=it2->second;
Pkt_ETED=(ArrivingTime-CreatingTime)/1000000000;
TotalTrafficETED.push_back(Pkt_ETED);
Pkt_creatingmap.erase(it->first);
Pkt_arrivalmap.erase(it2->first);
cout <<"Pkt_ID:"<<CreatingID<<","<<"Pkt_ETED:"<<Pkt_ETED<<endl;
}
}
Related
I'm trying to essentially iterate through every word in the .txt file and when I find a word (from my words map) with more than the maxwordcount variable I add it into the front of the topwords vector
int main(int argc, char** argv) {
fstream txtfile;
string filename = argv[1];
string word, tempword;
int maxwordcount = 0;
int wordcount = 0;
int uniquewordcount = 0;
vector<pair <string, int> > topwords;
map<string, int> words;
if (argc != 2) {
cout << "Incorrect number of arguments on the command line bud" << endl;
}else{
txtfile.open(filename.c_str());
if (txtfile.is_open()) {
while (txtfile >> word){
//removePunctuation(word);
//transform(word.begin(), word.end(), word.begin(), [](unsigned char c){ return::tolower(c); }); //makes string lowercase using iterator
if (words.find(word) == words.end()) {
words[word] = 1; //adds word into the map as a pair starting with a word count of 1
if (words[word] > maxwordcount) { //For case if word is the first word added to the map
maxwordcount = words[word]; //change maxwordcount
topwords.insert( topwords.begin(), make_pair(word, words[word]) ); //insert word into the front of the top words vector
cout << "word: '" << word << "' word-count: " << words[word] << endl;
}
uniquewordcount++;
}else{ //the word is found
words[word]++; //increment count for word by 1
if (words[word] > maxwordcount) { //check if wordcount > maxwordcount
topwords.insert( topwords.begin(), make_pair(word, words[word]) ); //insert word into the front of the top words vector
}
}
wordcount++;
}
At the end of the program I want to display top 10 or so words from the txt file. I tested whether the while loop was running by displaying a live wordcount (cout). The number was going up, but it was going up extremely slow. Also I'm using huge books for my txt files.
Image of results when running
I also don't completely understand inserting variables into maps and vectors, so something might be going wrong there.
I've hit a dead-end, so anything will help at this point.
I used a smaller text file too to test:
This is a small sentence to test test test
hey hey
Results:
word: 'This' word-count: 1
1
2
3
4
5
6
7
7
7
8
8
There were 11 words in the file.
There were 8 unique words in the file.
Top 20 words in little.txt:
hey 2
test 3
test 2
This 1
Segmentation fault
I know I'm doing something wrong, but I don't have a clue where to look next or what to test. Still an amateur at C++ and C too.
you should read the file by lines, process line by line
read file file by line: https://www.systutorials.com/how-to-process-a-file-line-by-line-in-c/
https://www.geeksforgeeks.org/split-a-sentence-into-words-in-cpp/
https://www.w3schools.com/cpp/cpp_functions.asp
https://www.w3schools.com/cpp/cpp_function_param.asp
https://www.w3schools.com/cpp/cpp_function_return.asp
https://www.w3schools.com/cpp/cpp_pointers.asp <--- very importend
https://www.w3schools.com/cpp/cpp_references.asp <--- likewise importend
#include <bits/stdc++.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <string>
#include <algorithm>
#include <sstream>
#include <regex>
#include <iterator>
using namespace std;
vector<std::pair <string, int> > topwords;
void store(vector<pair <string, int> > &topwords, string str){
auto pos = std::find_if(topwords.begin(), topwords.end(),
[str](std::pair<string, int> const &b) {
return b.first == str;
});
//std::cout<< pos->first << endl;
if(pos != topwords.end()){
std::cout << "word: " << pos->first << " " << pos->second << " found" << endl;
pos->second++;
}
else{
std::cout << "not found" << endl;
topwords.push_back( make_pair(str,1) );
}
}
void removeDupWord(string str)
{
// Used to split string around spaces.
istringstream ss(str);
// Traverse through all words
/*
do {
// Read a word
string word;
ss >> word;
// Print the read word
cout << word << endl;
store(topwords, word );
// While there is more to read
} while (ss);
*/
string word;
while (ss >> word) {
//cout << word << endl;
const std::regex sanitized{ R"([-[\]{}()*+?.,\^$|#\s])" };
std::stringstream result;
std::regex_replace(std::ostream_iterator<char>(result), word.begin(), word.end(), sanitized, "");
//store(topwords, word );
store(topwords, result.str() );
}
}
void readReadFile(string &fileName){
std::cout << "fileName" << fileName << endl;
std::ifstream file(fileName);
std::string str;
while (std::getline(file, str)) {
//std::cout << str << "\n";
removeDupWord(str);
//store(topwords, str);
}
}
bool compareFunction (const std::pair<std::string, int> &a, const std::pair<std::string, int> &b) {
return a.first<b.first; // sort by letter
}
bool compareFunction2 (const std::pair<std::string, int> &a, const std::pair<std::string, int> &b) {
return a.second>b.second; // sort by count
}
bool cmp(pair<string, int> &A, pair<string, int> &B) {
return A.second < B.second;
}
void check(vector<pair <string, int> > &topwords){
std::pair<string, int> mostUsedWord = make_pair("",0);
for(auto ii : topwords){
std::cout << "word: " << ii.first << " count: " << ii.second << endl;
if(ii.second > mostUsedWord.second){
mostUsedWord.first = ii.first;
mostUsedWord.second = ii.second;
}
}
std::cout << "most used Word: " << mostUsedWord.first << " x " << mostUsedWord.second << " Times." << endl;
}
void get_higestTopTenValues(vector<pair <string, int> > &topwords){
std::sort(topwords.begin(),topwords.end(),compareFunction2);//sort the vector by count
int MAX = std::max_element(topwords.begin(), topwords.end(), cmp)->second;
std::cout << "max: " << MAX << endl;
for(auto ii : topwords){
//std::cout << "word: " << ii.first << " count: " << ii.second << endl;
if(ii.second >= (MAX - 10)){
std::cout << ii.first << " " << ii.second << endl;
}
}
}
void get_LowestTopTenValues(vector<pair <string, int> > &topwords){
std::sort(topwords.begin(),topwords.end(),compareFunction2);//sort the vector by count
int MIN = std::min_element(topwords.begin(), topwords.end(), cmp)->second;
std::cout << "min: " << MIN << endl;
for(auto ii : topwords){
//std::cout << "word: " << ii.first << " count: " << ii.second << endl;
if(ii.second <= (MIN + 9)){
std::cout << ii.first << " " << ii.second << endl;
}
}
}
int main ()
{
std::string word, fileName;
fileName = "input.txt";
readReadFile(fileName);
topwords.push_back( make_pair("ba",1) );
topwords.push_back( make_pair("bu",1) );
topwords.push_back( make_pair("hmmm",1) );
topwords.push_back( make_pair("what",1) );
topwords.push_back( make_pair("and",1) );
topwords.push_back( make_pair("hello",1) );
word = "hellos";
store(topwords, word);
store(topwords, word);
store(topwords, word);
store(topwords, word);
word = "hello";
store(topwords, word);
store(topwords, word);
store(topwords, word);
store(topwords, word);
store(topwords, word);
store(topwords, word);
std::sort(topwords.begin(),topwords.end(),compareFunction);//sort the vector by letter
// or
//std::sort(topwords.begin(),topwords.end(),compareFunction2);//sort the vector by count
std::cout << "---------------------------------------" << endl;
std::cout << " get all values" << endl;
std::cout << "---------------------------------------" << endl;
check(topwords);
std::cout << "---------------------------------------" << endl;
std::cout << " get the top 10 highest values" << endl;
std::cout << "---------------------------------------" << endl;
get_higestTopTenValues(topwords);
std::cout << "---------------------------------------" << endl;
std::cout << " get the top 10 lowest values" << endl;
std::cout << "---------------------------------------" << endl;
get_LowestTopTenValues(topwords);
}
This question has his been aswered long time ago. I stumbled over the question and asnwer and I find everything overly complicated.
Therefore I would like to add a more modern C++ solution making use of existing STL elements.
This makes the code more compact.
Please see below:
#include <iostream>
#include <utility>
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <string>
#include <fstream>
const std::string fileName{"r:\\loremipsum.txt"};
int main() {
if (std::ifstream textFileStream{ fileName }; textFileStream) {
// Here we store the count of all words
std::unordered_map<std::string, size_t> counter{};
size_t countOfOverallWords{}; // Counter for the number of all words
// Read all words from file, remove punctuation, and count teh occurence
for (std::string word; textFileStream >> word; counter[word]++) {
word.erase(std::remove_if(word.begin(), word.end(), ispunct), word.end());
++countOfOverallWords;
}
// For storing the top 10
std::vector<std::pair<std::string, size_t>> top(10);
// Get top 10
std::partial_sort_copy(counter.begin(), counter.end(), top.begin(), top.end(),
[](const std::pair<std::string, size_t >& p1, const std::pair<std::string, size_t>& p2) { return p1.second > p2.second; });
// Now show result
std::cout << "Count of overall words:\t " << countOfOverallWords << "\nCount of unique words:\t " << counter.size() << "\n\nTop 10:\n";
for (const auto& t : top) std::cout << "Value: " << t.first << "\t Count: " << t.second << '\n';
}
else std::cerr << "\n\nError: Could not open source file '" << fileName << "'\n\n";
return 0;
}
Developed and tested with Microsoft Visual Studio Community 2019, Version 16.8.2.
Additionally compiled and tested with clang11.0 and gcc10.2 with flags --std=c++17 -Wall -Wextra -Wpedantic
Language: C++17
i am storing some data in the file but after
if (titlemap.count(words[i]) == 1)
is reached i reopened the file and reading all data in a vector and then storing updated data but
But actually the program is not going into the below loop.
for (int j = 0; j < vec.size(); j++)
Can anyone suggest why is it so? I am very confused and frustrated
// Cmarkup1.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include"Markup.h"
#include <msxml.h>
#include <ctime>
#include <unordered_map>
#include <cctype>
#include <string>
#include <functional>
#include <algorithm>
#include "functions.h"
#include <map>
#include <fileapi.h>
using namespace std;
int main()
{
// Open the file for parsing.
ofstream wfile("title.txt");
bool check = false;
string delimiter = " ,:,";
int results = 0, pages = 1;
time_t timer;
timer = clock();
CMarkup xmlfile;
unordered_map<string, string> titlemap;
unordered_map<string, string> textmap;
vector <string> words;
xmlfile.Load(MCD_T("simplewiki-latest-pages-articles.xml"));
xmlfile.FindElem();
xmlfile.IntoElem();
int line=0;
while (xmlfile.FindElem(MCD_T("page"))) {
xmlfile.IntoElem();
xmlfile.FindElem(MCD_T("title"));
MCD_STR(title);
title = xmlfile.GetData();
string str(title.begin(), title.end());
transform(str.begin(), str.end(), str.begin(), ::tolower);
split(words, str, is_any_of(delimiter));
for (int i = 0; i < words.size(); i++) {
if (titlemap.count(words[i]) == 1) {
ifstream rfile;
rfile.open("title.txt");
vector<string> vec;
string line;
while (getline(rfile, line)) {
vec.push_back(line);
}
for (int j = 0; j < vec.size(); j++) {
if (words[i] == vec[j]) {
cout << vec[j] <<"Checking"<< endl;
wfile << vec[j] << ",page" << pages << endl;
}
else
wfile << vec[j] << endl;
//wfile.close();
}
}
else {
//wfile.open("title.txt");
keeponlyalphabets(words[i]);
titlemap.insert(make_pair(words[i], words[i]));
wfile << words[i] <<"-page"<<pages<< endl;
++line;
}
}
words.clear();
//cout << str << endl;
//xmlfile.FindElem(MCD_T("text"));
//MCD_STR(text);
//text = xmlfile.GetData();
//string str1(text.begin(), text.end());
//transform(str1.begin(), str1.end(), str1.begin(), ::tolower);
//str1 = keeponlyalphabets(str1);
//removestopwords(str1);
//textmap.insert(make_pair(str1, str1));
//cout << str1 << endl;
if (pages > 100)
break;
pages++;
xmlfile.OutOfElem();
}
wfile.close();
// for (auto it : titlemap)
// cout << it.first << endl;
cout << "Total lines are as: "<<line << endl;
/*string input;
cout << "press s to seach the data" << endl;
getline(cin, input);
if (input == "s") {
string key;
cout << "Enter Key" << endl;
cin >> key;
transform(key.begin(), key.end(), key.begin(), ::tolower);
size_t temp;
cout << endl;
for (auto it = data.begin(); it != data.end(); it++) {
//temp = it->first.find(key);
//cout << temp;
if (it->first.find(key) != std::string::npos) {
cout << it->second << endl;
results++;
}
}
}
else
cout << "Invalid Character Exiting....." << endl;
timer = clock() - timer;
cout << "Total time taken by the process is: " << (float)timer / CLOCKS_PER_SEC << endl;
cout << " Total Results : " << results << endl;
*/
return 0;
}
You have separate streams opened against the file, with separate buffers on each. writeing to a file only actually writes to disk infrequently (typically when a buffer fills, which may take a while for small writes, and always just before the file is closed). So when you re-open the file for read, it won't see anything still stuck in user-space buffers.
Just add:
wfile.flush()
prior to opening for read, to ensure the buffers are flushed to disk and available to the alternate handle.
I'm somewhat new to vectors and iterators and I'm trying to figure out how to display an amount of items using an iterator. One example would be you have 5 apples. I would want it to output "5x Apple" or something of that sort. I have no idea how one might accomplish this. Here's a simple code that has the user put in a string to add to the inventory.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string item;
vector<string> inventory;
vector<string>::iterator iter;
int main()
{
while(true){
cin >> item;
inventory.push_back(item);
cout << "INVENTORY:\n";
for(iter = inventory.begin(); iter != inventory.end(); iter++)
cout << *iter << endl;
}
}
EDIT: I'm trying to make an inventory system for a game. That's why I thought i may need an iterator. If there's a better way to make an inventory system than using an iterator, please let me know. Apologies, i should have clarified.
An iterator lets you iterate through a container, but it does not do any counting for you.
A container's size() tells you how many items are in the container, but if you have different types of items then you have to count them yourself.
For instance, say you have 4 "apple" and 1 "orange".
You have to look at each item entered and count it as needed, eg:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> inventory;
int numApples = 0;
int numOranges = 0;
int numOther = 0;
int main()
{
string item;
while (cin >> item)
{
inventory.push_back(item);
if (item == "apples")
++numApples;
else if (item == "orange")
++numOranges;
else
++numOther;
}
cout << "INVENTORY:\n";
for (vector<string>::iterator iter = inventory.begin(); iter != inventory.end(); ++iter)
cout << *iter << endl;
/* or, if you are using C++11 or later:
for (string &s : inventory)
cout << s << endl;
*/
cout << "# apples: " << numApples << endl;
cout << "# oranges: " << numOranges << endl;
cout << "# other: " << numOther << endl;
return 0;
}
Or, you might consider using std::count_if(), eg:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> inventory;
bool isApple(const string &s) { return (s == "apple"); }
bool isOrange(const string &s) { return (s == "orange"); }
bool isOther(const string &s) { return !(isApple(s) || isOrange(s)); }
int main()
{
string item;
while (cin >> item)
inventory.push_back(item);
cout << "INVENTORY:\n";
for (vector<string>::iterator iter = inventory.begin(); iter != inventory.end(); ++iter)
cout << *iter << endl;
/* or, if you are using C++11 or later:
for (string &s : inventory)
cout << s << endl;
*/
cout << "# apples: " << count_if(inventory.begin(), inventory.end(), isApple) << endl;
cout << "# oranges: " << count_if(inventory.begin(), inventory.end(), isOrange) << endl;
cout << "# other: " << count_if(inventory.begin(), inventory.end(), isOther) << endl;
/* or, if you are using C++11 or later:
cout << "# apples: " << count_if(inventory.begin(), inventory.end(), [](auto &s){ return (s == "apple"); }) << endl;
cout << "# oranges: " << count_if(inventory.begin(), inventory.end(), [](auto &s){ return (s == "orange"); }) << endl;
cout << "# other: " << count_if(inventory.begin(), inventory.end(), [](auto &s){ return (s != "apple") && (s != "orange"); }) << endl;
*/
return 0;
}
Update: based on another question you posted, try something more like this instead:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> other_inventory;
int numApples = 0;
int numOranges = 0;
int main()
{
string item;
while (cin >> item)
{
if (item == "apples")
++numApples;
else if (item == "orange")
++numOranges;
else
other_inventory.push_back(item);
}
cout << "INVENTORY:\n";
if (numApples > 0)
cout << "# apples: " << numApples << endl;
if (numOranges > 0)
cout << "# oranges: " << numOranges << endl;
for (vector<string>::iterator iter = other_inventory.begin(); iter != other_inventory.end(); ++iter)
cout << *iter << endl;
/* or, if you are using C++11 or later:
for (string &s : other_inventory)
cout << s << endl;
*/
return 0;
}
A way to simplify this is to sort the items in the inventory. That will bring the identical ones together, which simplifies counting them. Start at the beginning, count the number of consecutive items that match the current one, display it, and continue with the first non-matching one.
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::string item;
std::vector<std::string> inventory;
while (true) {
std::cin >> item;
if (item == "quit") return 0;
inventory.push_back(item);
std::sort(inventory.begin(), inventory.end());
std::cout << "INVENTORY:\n";
auto current = inventory.begin();
while (current != inventory.end()) {
int count = 1;
auto probe = current + 1;
while (probe != inventory.end() && *probe == *current) {
++count;
++probe;
}
std::cout << count << "x " << *current << '\n';
current = probe;
}
std::cout.flush();
}
return 0;
}
In more detail, if your inventory is {"orange", "apple", "orange"}, then the sort will rearrange the order to {"apple", "orange", "orange"}. Note that the identical ones are together.
Now the iterator current starts at the beginning ("apple"). We set count to 1 because we know there's at least 1. We set the iterator probe to point to the next item ("orange"). Since the value at probe doesn't match the value at current, the inner loop does nothing. We print count and the current item ("apple"). We continue by setting current to probe, because, at this point, probe will point to the first item that didn't match the current one.
On the second iteration, current refers to the first "orange". We reset count to 1 and start probe at the next item ("orange"). Since the values at match, we increment count (now 2) and advance probe (now at the end of the inventory). We print count (2) and the current item ("orange"), and set current to probe (end of the list). The outer loop condition sees we're at the end of the inventory, so the loop terminates.
inventory.size()
returns the number of items in your vector.
I don't see how you would need an iterator for that task.
I am using the following code to cound the frequency of words :
// Program for Owen written by Briana Morrison
//#pragma warning (disable : 4786)
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <algorithm>
#include <vector>
using namespace std;
// program assumes that the filename is the only thing passed into program
// if you are using standard argc and argv, then arguments to main should change, and uncomment
// first line.
int main(int argc, char * argv[])
{
string filename(argv[1]);
// string filename;
//cout << "Enter filename" << endl;
//cin >> filename;
ifstream infile(filename.c_str());
//ifstream infile("poe.txt");
string word;
bool debug = false; // for debugging purposes
int count = 0; // count of words for debugging
// create a map of words to frequencies
map<string, int, less<string> > words;
// create a multimap of frequencies to words
multimap<int, string, greater<int> > freq;
// loop while there is input in the file
infile >> word; //priming read
while (infile)
{
count++;
// convert word to lowercase
for (int i = 0; i < word.length(); i++)
if ('A' <= word[i] && word[i] <= 'Z')
word[i] = tolower(word[i]);
if (debug) cout << word << endl;
// if word not found, add to map, otherwise increment count
if (words.find(word) != words.end())
{
words[word]++;
if (debug) cout << word << " found and count incremented to " << words[word] << endl;
}
else
{
words[word] = 1;
if (debug) cout << word << " not found and count incremented to " << words[word] << endl;
}
infile >> word;
}
if (debug) cout << "count is " << count << " and map has " << words.size() << endl;
// now go through map and add everything to multimap...words still in alphabetical order
map<string, int, less<string> >::iterator it = words.begin();
for (it = words.begin(); it != words.end(); it++)
{
pair<int, string> p(it->second, it->first);
freq.insert(p);
}
if (debug) cout << "map has " << words.size() << " and multimap has " << freq.size() << endl;
ofstream outfile("myout.txt");
multimap<int, string, greater<int> >::iterator myit=freq.begin();
for (myit = freq.begin(); myit != freq.end(); myit++)
{
outfile << myit->first << "\t" << myit->second << endl;
}
outfile.close();
return 0;
}
The problem is not in here I think
When i am writing the words to a file, it gets slower by every iteration why?
ofstream outfile("myout.txt");
multimap<int, string, greater<int> >::iterator myit=freq.begin();
for (myit = freq.begin(); myit != freq.end(); myit++)
{
outfil<< myit->first << "\t" << myit->second << endl;
}
outfile.close();
How can I write the multimap in a fast way to a file?
You can use '\n' instead of std::endl to avoid flushing it for every line.
outfil << myit->first << '\t' << myit->second << '\n';
for (myit = freq.begin(); myit != freq.end(); ++myit)
{
outfil<< myit->first << "\t" << myit->second << "\n";
}
this should be faster.
Or you can buffer the data and write them all at once, not line by line.
I don't see why your loop should get slower with every single iteration, but note that you're using formatted output (which is what operator<< does), which is notoriously slow. In case your strings don't contain null bytes you could make your code more efficient by writing the std::string via ostream::write i.e.
outfil << myit->first;
outfil.write( "\t", 1 );
outfil.write( myit->second.c_str(), myit->second.size() );
outfil.write( "\n", 1 );
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <map>
using namespace std;
int main()
{
ifstream fin;
fin.open("myTextFile.txt");
if ( fin.fail()){
cout << "Could not open input file.";
exit(1);
}
string next;
map <string, int> words;
while (fin >> next){
words[next]++;
}
cout << "\n\n" << "Number of words: " << words[next] << endl;
fin.close();
fin.open("myTextFile.txt");
while (fin >> next){
cout << next << ": " << words[next] << endl;
}
fin.close();
return 0;
}
My main problem is that when a word occurs more than once, it is also listed more then once. i.e if the text starts with "hello hello" then cout produces:
"hello: 2" '\n' "hello: 2"
Also, i'd like not to have to close, and then reopen the file for the second while to be true. It seems like its still at the end of the file from the last while loop.
You need to iterate trough the map, and not open the file a second time.
Look at the code sample provided here.
EDIT: here a code sample that iterates trough a map
// map::begin/end
#include <iostream>
#include <map>
int main ()
{
std::map<char,int> mymap;
std::map<char,int>::iterator it;
mymap['b'] = 100;
mymap['a'] = 200;
mymap['c'] = 300;
// show content:
for (std::map<char,int>::iterator it=mymap.begin(); it!=mymap.end(); ++it)
std::cout << it->first << " => " << it->second << '\n';
return 0;
}
Here is the output:
a => 200
b => 100
c => 300
You don't need re-open file:
for (auto i = words.begin(); i != words.end(); i++)
{
cout << i->first << " : " << i->second << endl;
}
or simpler:
for (const auto &i : words)
{
cout << i.first << " : " << i.second << endl;
}
You need to iterate over the map after you set it and then you do not need to open the file again, this is trivial example:
int main()
{
std::map<std::string, int> m1 ;
m1["hello"] = 2 ;
m1["world"] = 4 ;
for( const auto &entry : m1 )
{
std::cout << entry.first << " : " << entry.second << std::endl ;
}
}
The expected output would be:
hello : 2
world : 4