I made a program that takes data from file, puts it into vector and then checks for most frequent element in the vector. (using map)
The problem is when I have same number of elements in the data (two Element1, two Element2, one Element3). It returns Element1 and I need it to pass the information that there is "no most frequent element".
My code looks like:
using namespace std;
bool comp(const pair<string, unsigned long> &pair1,
const pair<string, unsigned long> &pair2) {
return pair1.second < pair2.second;
}
string Odczyt::tokenizer() {
inFile.open("baza.txt");
while (!inFile.eof()) {
for (int i = 0; i < 4; i++) {
inFile >> row1[i] >> row2[i] >> row3[i] >> row4[i];
}
}
sVector1.assign(row1, row1 + 3);
string w1 = most_occurred(sVector1);
return w1;
}
string Odczyt::most_occurred(vector<string> &vec) {
map<string, unsigned long> str_map1;
for (vector<string>::const_iterator it = vec.begin(); it != vec.end();
++it) {
++str_map1[*it];
}
return max_element(str_map1.begin(), str_map1.end(), comp)->first;
}
Create a variable which stores the number of times you have found an element which occurs m times (where m is the current maximum number of times any element has occurred). If at the termination point of the algorithm you have more than one element appearing m times, then you know there is no single most-frequently-occurring element.
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
string most_occurred(vector<string> &vec) {
map<string, unsigned long> str_map1;
std::string max_element = "";
int max_count = 0;
typedef vector<string>::const_iterator iter;
iter end = vec.end();
for (iter it = vec.begin(); it != end; ++it) {
int count = ++str_map1[*it];
if(count == max_count) max_element = "no max found";
if(count > max_count) {
max_count = count;
max_element = *it;
}
}
return max_element;
}
int main() {
std::string arr1[5] = {"aa" , "bb", "cc", "dd", "ee"}; // no max found
std::string arr2[5] = {"aa" , "aa", "cc", "dd", "ee"};// aa
std::string arr3[5] = {"aa" , "aa", "cc", "cc", "ee"}; // no max found
std::vector<std::string> input1(arr1, arr1+5);
std::vector<std::string> input2(arr2, arr2+5);
std::vector<std::string> input3(arr3, arr3+5);
std::cout << most_occurred(input1) << std::endl;
std::cout << most_occurred(input2) << std::endl;
std::cout << most_occurred(input3) << std::endl;
}
the result is:
no max found
aa
no max found
The following test resulted in no max found.
int main() {
std::string arr1[24] = {"Element1", "Element2", "Element33", "1",
"Element1", "Element2", "Element33", "2", "Element11", "Element2",
"Element33", "2", "Element11" "Element21" "Element31", "2", "Element11",
"Element21", "Element31", "1", "Element12", "Element21", "Element31",
"1"}; // no max found
std::vector<std::string> input1(arr1, arr1+24);
std::cout << most_occurred(input1) << std::endl;
}
If the above code returns std::string("") then there was no max element, else it will return the max.
This is a frequent operation here is my sample code:
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <iterator>
using namespace std;
int main(int argc, char* argv[]) {
// number -> frequency
map<int, int> idfreq = {{1, 3}, {2, 10}, {3,8}, {9, 15}, {7,30}};
vector<pair<int, int> > v;
copy(idfreq.begin(), idfreq.end(), back_inserter(v));
for (auto& el : v) {
cout << el.first << " " << el.second << endl;
}
cout << endl;
make_heap(v.begin(), v.end(), [](const pair<int,int> &a, const pair<int,int> &b){ return a.second < b.second; });
// with -std=c++14
//make_heap(v.begin(), v.end(), [](auto& a, auto& b){ return a.second < b.second; });
cout << v.front().first << " " << v.front().second << " most frequent element\n";
cout << "after make heap call\n";
for (auto& el : v) {
cout << el.first << " " << el.second << endl;
}
cout << endl;
return 0;
}
Related
I essentially want to group the elements of the multimap by key, and obtain the new data structure as a map.
the multimap:
std::multimap<std::string,std::vector<int>> multiMap;
VecA VecB
ABC 10 30
ABC 10 30
DEF 20 20
the output required:
std::map<std::string,std::vector<int>> map;
VecA VecB
ABC 20 60
DEF 20 20
The following code works for a std::multimap<std::string,int>
std::vector<std::string> a = {ABC,ABC,DEF,GHI};
std::vector<int> b = {10,20,30,40};
std::multimap<std::string,int> multiMap;
for (int i = 0; i < a.size(); i++)
{
multiMap.insert(std::pair<std::string,int >(a[i], b[i]));
}
std::map<std::string,int> map;
std::for_each
(
multiMap.begin(),
multiMap.end(),
[&map] (auto const & i)
{
map[i.first] += i.second;
}
);
I am unable to change the code in line 19 of the above block (i.e. in the lambda function) to extend in the case of std::multimap<std::string,std::vector<int>> to std::map<std::string,std::vector<int>>
If you want use Arithmetic operators
Use valarray
Demo: https://wandbox.org/permlink/SAnHNKNZ0UufqZsN
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <valarray>
#include <numeric>
int main()
{
using key_type = std::valarray<int>;
key_type b = {10,20,30,40};
auto containerToStr = [](const auto& cont)
{
return std::accumulate(std::begin(cont), std::end(cont), std::string{}, [](const auto& str, const auto& val){
return str + " " + std::to_string(val);
});
};
std::multimap<std::string,key_type> multiMap;
std::vector<std::string> a = {"ABC","ABC","DEF","GHI"};
for (size_t i = 0; i < a.size(); i++)
{
multiMap.insert(std::pair<std::string,key_type >(a[i], b));
}
std::cout << "Before sum" << std::endl;
for (const auto& p : multiMap)
std::cout << p.first << " " << containerToStr(p.second) << std::endl;
std::cout << std::endl;
std::map<std::string,key_type> map;
std::for_each( multiMap.begin(), multiMap.end(), [&map] (auto const & i)
{
// map[i.first] += i.second; // caution map[i.first] create an empty key_type
if ( map.count(i.first) > 0)
{
map.at(i.first) += i.second;
}
else
{
map.insert({i.first, i.second});
}
}
);
std::cout << "After sum" << std::endl;
for (const auto& p : map)
std::cout << p.first << " " << containerToStr(p.second) << std::endl;
}
If you want use std::vector
Define your sum function.
Demo: https://wandbox.org/permlink/FteFkLfwQh0P4wzp
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <numeric>
int main()
{
using key_type = std::vector<int>;
key_type b = {10,20,30,40};
auto containerToStr = [](const auto& cont)
{
return std::accumulate(std::begin(cont), std::end(cont), std::string{}, [](const auto& str, const auto& val){
return str + " " + std::to_string(val);
});
};
std::multimap<std::string,key_type> multiMap;
std::vector<std::string> a = {"ABC","ABC","DEF","GHI"};
for (size_t i = 0; i < a.size(); i++)
{
multiMap.insert(std::pair<std::string,key_type >(a[i], b));
}
std::cout << "Before sum" << std::endl;
for (const auto& p : multiMap)
std::cout << p.first << " " << containerToStr(p.second) << std::endl;
std::cout << std::endl;
std::map<std::string,key_type> map;
// Warning : naive function, to rework
auto your_sum = [](const auto& cont1, const auto& cont2)
{
key_type result;
const auto smaller = std::min(cont1.size(), cont2.size());
for ( size_t i = 0 ; i < smaller; i++)
{
result.push_back(cont1[i]+cont2[i]);
}
return result;
};
std::for_each( multiMap.begin(), multiMap.end(), [&map,&your_sum] (auto const & i)
{
// map[i.first] += i.second; // caution map[i.first] create an empty key_type
if ( map.count(i.first) > 0)
{
map.at(i.first) = your_sum(i.second, map.at(i.first));
}
else
{
map.insert({i.first, i.second});
}
}
);
std::cout << "After sum" << std::endl;
for (const auto& p : map)
std::cout << p.first << " " << containerToStr(p.second) << std::endl;
}
using namespace std;
int main()
{
list<int> numbers; list<int> numb;
for (int i = 0; i<10; i++)
numbers.push_back(rand() % 20);
list<int>::iterator it;
for (it = numbers.begin(); it != numbers.end(); ++it)
{
cout << *it << " ";
}
return 0;
}
I wanted to use std::count() but I am not able to do it right. I tried to do the following:
using namespace std;
int main()
{
list<int> numbers; list<int> numb;
for (int i = 0; i<10; i++)
numbers.push_back(rand() % 20);
list<int>::iterator it;
for (it = numbers.begin(); it != numbers.end(); ++it)
{
cout << *it << " ";
while (it != numbers.begin() && it != numbers.end())
{
++it;
*it = count(it, numbers.begin(), numbers.end());
cout << " " << *it;
}
cout << endl;
}
return 0;
}
But it gives me an error:
binary == no operator found which takes a left hand operator type 'int' (or there is not acceptable conversion).
I know I am doing something wrong.
I also tried a few more things, like int numb = std::count(numbers.begin()), numbers.end(), *it), but it didn't work either. So, I want to know if there is a special operator to count values in a list.
You need to look at the signature for std::count again. It takes three parameters std::count(InputIterator first, InputIterator last, const T& val); and it returns the number of occurrences of val in your data set. So something like this should work for you where theNumber is the number you're counting.
#include <algorithm>
int occurrences = std::count(numbers.begin(), numbers.end(), theNumber);
You are not using iterators correctly (you are modifying it while you are still using it to iterate the list), and you are not calling std::count() correctly.
The code should look more like this instead:
#include <iostream>
#include <list>
#include <algorithm>
#include <cstdlib>
int main()
{
std::list<int> numbers;
int numb;
for (int i = 0; i < 10; i++)
numbers.push_back(std::rand() % 20);
std::list<int>::iterator it;
for (it = numbers.begin(); it != numbers.end(); ++it)
{
numb = std::count(numbers.begin(), numbers.end(), *it);
std::cout << *it << " " << numb << std::endl;
}
/* or:
for (int value : numbers)
{
numb = std::count(numbers.begin(), numbers.end(), value);
std::cout << value << " " << numb << std::endl;
}
*/
return 0;
}
But, like others said, you should use a std::map to track the counts, so you can account for duplicates, eg:
#include <iostream>
#include <list>
#include <map>
#include <cstdlib>
int main()
{
std::list<int> numbers;
std::map<int, int> numb;
for (int i = 0; i < 10; i++)
numbers.push_back(rand() % 20);
for (std::list<int>::iterator it = numbers.begin(); it != numbers.end(); ++it)
numb[*it]++;
/* or:
for (int value : numbers)
numb[value]++;
*/
for (std::map<int, int>::iterator it = numb.begin(); it != numb.end(); ++it)
std::cout << it->first << " " << it->second << std::endl;
/* or:
for (auto &item : numb)
std::cout << item.first << " " << item.second << std::endl;
*/
return 0;
}
Which can be reduced to this:
#include <iostream>
#include <map>
#include <cstdlib>
int main()
{
std::map<int, int> numb;
for (int i = 0; i < 10; i++)
numb[rand() % 20]++;
for (std::map<int, int>::iterator it = numb.begin(); it != numb.end(); ++it)
std::cout << it->first << " " << it->second << std::endl;
/* or:
for (auto &item : numb)
std::cout << item.first << " " << item.second << std::endl;
*/
return 0;
}
In general, using a map is a better approach to your problem, but if you have to solve it using lists here is one possible solution:
#include <iostream>
#include <algorithm>
#include <list>
int main()
{
std::list<int> numbers, unique_num, numb;
int num;
// Create both the original list and a list that
// will be left with only unique numbers
for (int i = 0; i<10; i++){
num = rand() % 20;
numbers.push_back(num);
unique_num.push_back(num);
}
// Sort and select the unique numbers
unique_num.sort();
unique_num.unique();
// Count unique numbers and store the count in numb
std::list<int>::iterator iter = unique_num.begin();
while (iter != unique_num.end())
numb.push_back(count(numbers.begin(), numbers.end(), *iter++));
// Print the results
for(std::list<int>::iterator iter1 = unique_num.begin(), iter2 = numb.begin();
iter2 != numb.end(); iter1++, iter2++)
std::cout<< "Number " << *iter1 << " appears " <<
*iter2 << ( *iter2 > 1 ? " times " : " time" ) << std::endl;
return 0;
}
The program uses another list, unique_num, to hold unique numbers occurring in numbers. That list is initially created identical to numbers and is then sorted and the duplicates are removed.
The program then iterates through numbers in that unique list and uses count to get the number of occurrences of each of them in the original numbers list. The number of occurrences is then stored in a new list, numb.
When printing, the program uses a ternary operator to check whether it should print "time" or "times" depending whether the result implies one or more than one occurrence.
Note - if you want different list values each time you run your program you need to change the random seed using srand. Include the header #include <time.h> in your program and the line srand(time(NULL)); at the beginning of your main.
I suggest you use a map:
map<int, int> counts;
for(int val : Numbers)
++counts[val];
WITH ADDITIONAL MEMORY:
You can use buckets, to get complexity O(N + MAX_NUM). So when MAX_NUM <= N we have O(N):
#include <iostream>
#include <list>
#include <algorithm>
#include <ctime>
const int MAX_NUM = 20;
const int N = 10;
int main() {
std::list<int> numbers;
int buckets[MAX_NUM];
std::fill(buckets, buckets + MAX_NUM, 0);
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// computing
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
buckets[*it]++;
}
//printing answers
for (int i = 0; i < MAX_NUM; i++) {
if (buckets[i]) std::cout << "value " << i << " appears in the list " << buckets[i] << " times." <<std::endl;
}
return 0;
}
For big data i would recommend using std::unordered_map for buckets and then geting complexity O(N) (thanks to hashing):
#include <iostream>
#include <list>
#include <algorithm>
#include <ctime>
#include <unordered_map>
const int N = 10;
const int MAX_NUM = 20;
int main() {
std::list<int> numbers;
std::unordered_map<int, int> buckets;
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// computing
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
buckets[*it]++;
}
//printing answers
for (auto & k_v : buckets) {
std::cout << "value " << k_v.first << " appears in the list " << k_v.second << " times." <<std::endl;
}
return 0;
}
WITHOUT ADDITIONAL MEMORY:
In more universal way, you can use std::vector instead of std::list and std::sort on it, and then count value changes in a simple for. Complexity is O(N log N):
#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
const int N = 10;
const int MAX_NUM = 20;
int main() {
std::vector<int> numbers;
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// sorting
std::sort(numbers.begin(), numbers.end());
//printing answers for sorted vector
if (numbers.size() > 0) {
int act_count = 1;
for (int i = 1; i < numbers.size(); i++) {
if (numbers[i] != numbers[i -1]) {
std::cout << "value " << numbers[i-1] << " appears in the list " << act_count << " times." <<std::endl;
act_count = 1;
} else {
act_count++;
}
}
std::cout << "value " << numbers[numbers.size() - 1] << " appears in the list " << act_count << " times." <<std::endl;
}
return 0;
}
You can also do the above on std::list, getting also O(nlogn), but can't use std::sort:
#include <iostream>
#include <list>
#include <ctime>
const int N = 10;
const int MAX_NUM = 20;
int main() {
std::list<int> numbers;
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// sorting
numbers.sort();
//printing answers for sorted list
if (!numbers.empty()) {
int act_count = 0;
auto prev = numbers.begin();
for (auto it = numbers.begin(); it != numbers.end(); it++) {
if (*it != *prev) {
std::cout << "value " << *it << " appears in the list " << act_count << " times." <<std::endl;
act_count = 1;
} else {
act_count++;
}
prev = it;
}
std::cout << "value " << *prev << " appears in the list " << act_count << " times." <<std::endl;
}
return 0;
}
I ran into the following problem: suppose I have
pair<int, int> p(1,2)
vector<pair<int, int>> vec;
I want to use find to get the iterator pointing to the element p in the vector
find(vec.begin(), vec.end(), p)
But it gave me the error
type 'std::__1::pair<int, int>' does not provide a call operator
How should I proceed?
This is what I've used and it's worked great.
#include <iostream>
#include <vector>
#include <algorithm>
struct FindPair {
FindPair (int first, int second)
: m_first_value(first)
, m_second_value(second) { }
int m_first_value;
int m_second_value;
bool operator()
( const std::pair<int, int> &p ) {
return (p.first == m_first_value && p.second == m_second_value);
}
};
int main()
{
std::vector< std::pair<int, int> > myVec;
std::vector< std::pair<int, int> >::iterator it;
myVec.push_back(std::make_pair(1,1));
myVec.push_back(std::make_pair(1,2));
it = std::find_if(myVec.begin(), myVec.end(), FindPair(1, 2));
if (it != myVec.end())
{
// We Found it
std::cout << "Matched Found on Current Iterator!" << std::endl;
std::cout << "it.first: " << (*it).first << std::endl;
std::cout << "it.second: " << (*it).second << std::endl;
}
else
{
std::cout << "Nothing Matched!" << std::endl;
}
return 0;
}
Output:
Matched Found on Current Iterator!
it.first: 1
it.second: 2
I want to delete all elements which pair first == 0
Here code:
int main()
{
map<char, pair<int,string>> myMap;
map<char, pair<int,string>>::const_iterator it;
for (int i = 0; i < 10; i++)
{
char c = 'a' + i;
pair<int,string> p = make_pair(rand() % 2, "dd");
myMap.insert(make_pair(c,p));
}
it = find_if(myMap.begin, myMap.end(), isEqual);
}
bool isEqual(const pair<char, pair<int, string> > element)
{
return element.second.first == 0;
}
Error:
/usr/include/c++/4.8/bits/stl_algo.h:150: error: could not convert
'__first.std::_Rb_tree_iterator<_Tp>::operator*<std::pair<const char,
std::pair<int, std::basic_string<char> > > >()' from 'std::pair<const
char, std::pair<int, std::basic_string<char> > >' to 'std::pair<int,
std::basic_string<char> >'
while (__first != __last && !bool(__pred(*__first)))
Yes, of course.
I think I'd write the code something like this (I've added a bit of extra code to print out the contents of the map before and after the deletion to show that it worked):
#include <map>
#include <utility>
#include <iostream>
#include <stdlib.h>
#include <string>
#include <algorithm>
#include <iterator>
#include <vector>
using namespace std;
ostream &operator<<(ostream &os, pair<int, string> const &p) {
return os << "[" << p.first << ", " << p.second << "]";
}
int main() {
map<char, pair<int, string>> myMap;
for (int i = 0; i < 10; i++) {
char c = 'a' + i;
pair<int, string> p = make_pair(rand() % 2, "dd");
myMap.insert(make_pair(c, p));
}
std::cout << "before:\n";
for (auto const &p : myMap)
std::cout << p.first << ": " << p.second << "\n";
map<char, pair<int, string> >::iterator it;
while (myMap.end() != (it = find_if(myMap.begin(), myMap.end(), [](auto p) { return p.second.first == 0; })))
myMap.erase(it);
std::cout << "\nafter\n\n";
for (auto const &p : myMap)
std::cout << p.first << ": " << p.second << "\n";
}
I would do this with a simple loop. You need to remember to keep track of the iterator when you erase an element from the map:
#include <map>
#include <ctime>
#include <string>
#include <vector>
#include <cstdlib>
#include <iostream>
#include <algorithm>
int main()
{
std::srand(std::time(0));
std::map<char, std::pair<int, std::string>> myMap;
for(int i = 0; i < 10; i++)
{
char c = 'a' + i;
auto p = std::make_pair(rand() % 2, "dd");
myMap.insert(std::make_pair(c, p));
}
std::cout << "\nbefore:\n";
for(auto const& p: myMap)
{
std::cout << p.first;
std::cout << " {" << p.second.first;
std::cout << ", " << p.second.second;
std::cout << "}" << '\n';
}
// remove items in a simple loop
for(auto iter = myMap.begin(); iter != myMap.end();)
{
if(iter->second.first == 0)
iter = myMap.erase(iter); // grab new iterator when erasing
else
++iter; // otherwise just increment
}
std::cout << "\nafter:\n";
for(auto const& p: myMap)
{
std::cout << p.first;
std::cout << " {" << p.second.first;
std::cout << ", " << p.second.second;
std::cout << "}" << '\n';
}
}
Example Output:
before:
a {0, dd}
b {1, dd}
c {0, dd}
d {0, dd}
e {1, dd}
f {0, dd}
g {0, dd}
h {1, dd}
i {0, dd}
j {0, dd}
after:
b {1, dd}
e {1, dd}
h {1, dd}
This question already has answers here:
Right way to split an std::string into a vector<string>
(12 answers)
Closed 7 years ago.
I'm writing 2 programs, the first program has an array of integers
vector<int> v = {10, 200, 3000, 40000};
Then it converts the vector into string
int i;
stringstream sw;
string stringword;
for (i=0;i<v.size();i++)
{
sw << v[i] << ',';
}
stringword = sw.str();
cout << "Vector in string : "<< stringword << endl;
And then write it in a file
ofstream myfile;
myfile.open ("writtentext");
myfile << stringword;
myfile.close();
The output :
Vector in string : 10,200,3000,40000
The second program will read the file, convert the string back to integer, and then push it back to vector.
The code :
string stringword;
ifstream myfile;
myfile.open ("writtentext");
getline (myfile,stringword);
cout << "Read From File = " << stringword << endl;
cout << "Convert back to vector = " ;
for (int i=0;i<stringword.length();i++)
{
if (stringword.find(','))
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(','));
}
}
for (int j=0;j<v.size();j++)
{
cout << v.at(j) << " " ;
}
The problem is, it can only convert and push back the first element, the rest is erased. Here is the output :
Read From File = 10,200,3000,40000,
Convert back to vector = 10
What did I do wrong? Thanks
There's problem with your for loop
Consider this:
while(1) //Use a while loop, "i" isn't doing anything for you
{
//if comman not found find return string::npos
if (stringword.find(',')!=std::string::npos)
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
//Erase all element including comma
stringword.erase(0, stringword.find(',')+1);
}
else
break; //Come out of loop
}
Instead, just use std::stringstream to read back from file
std::stringstream ss(stringword);
int value;
while (ss >> value)
{
v.push_back(value);
if (ss.peek() == ',')
ss.ignore();
}
for (int j=0;j<v.size();j++) //Fix variables
{
cout << v.at(j) << " " ; // Can use simply v[j]
}
for (int j=0;j<v.size();i++)
{
cout << v.at(i) << " " ;
}
should be
for (int j=0;j<v.size();j++)
{
cout << v.at(j) << " " ;
}
i is not declared in the for loop
You can skip the string conversion. All stream can handle int types.
std::vector<int> to output:
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
std::ostream_iterator<int> output_iterator(std::cout, ",");
std::copy(v.begin(), v.end(), output_iterator);
}
input to std::vector<int>:
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
int main() {
std::vector<int> v;
int value;
std::string line;
while(getline(cin, line, ',')) {
std::stringstream ss(line);
ss >> value
v.push_back(value);
}
typedef std::vector<int>::iterator iter;
iter end = v.end();
for(iter it = v.begin(); it != end; ++it) {
std::cout << *it << endl;
}
}
this is only a mistake you did:
for (int j=0;j<v.size();i++)
{
cout << v.at(i) << " " ;
}
but the implement is too inefficient here:
for (int i=0;i<stringword.length();i++)
{
if (stringword.find(','))
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(','));
}
}
you may do like this, just a suggestion:
#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>
int ConvertStringToInt(const std::string &str, std::vector<int> &ints)
{
int count_int = 0;
std::string string_int;
size_t start = 0;
size_t end = 0;
while ((end = str.find(',', start)) != std::string::npos)
{
string_int.assign(str, start, end - start);
ints.push_back(atoi(string_int.c_str()));
start = end + 1;
++count_int;
}
if (start != str.size())
{
ints.push_back(atoi(str.c_str() + start));
++count_int;
}
return count_int;
}
int main(int argc, char *const argv[])
{
std::vector<int> ints;
std::string str = "123,456,789 ";
std::cout << ConvertStringToInt(str, ints) << std::endl;
for (size_t i = 0; i != ints.size(); ++i)
{
std::cout << ints[i] << std::endl;
}
return 0;
}
You can make your programs simpler:
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>
// output
int main()
{
// my compiler doesn't support initializer lists yet :(
std::vector<int> v(4);
v[0] = 10;
v[1] = 200;
v[2] = 3000;
v[3] = 40000;
std::ofstream fout("mytestfile.txt");
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(fout, ","));
fout.close();
return 0;
}
// input
struct int_reader : std::ctype<char>
{
int_reader() : std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());
rc[','] = std::ctype_base::space;
rc['\n'] = std::ctype_base::space;
return &rc[0];
}
};
int main()
{
std::vector<int> v;
std::ifstream fin("mytestfile.txt", std::ifstream::in);
fin.imbue(std::locale(std::locale(), new int_reader()));
std::copy(std::istream_iterator<int>(fin), std::istream_iterator<int>(), std::back_inserter<std::vector<int>>(v));
fin.close();
std::cout << "You read in: ";
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
return 0;
}
Though this is handcrafted instead of using std::stringstream, I find it quite easy to understand.
std::vector<std::string> StringToVector (const std::string s,
const char token)
{
std::vector<std::string> v;
size_t posLast = 0, pos = 0;
while((pos = s.find(token, pos)) != std::string::npos)
{
if(s[pos] != s[posLast])
v.push_back(s.substr(posLast, pos - posLast));
posLast = ++pos;
}
if(s[posLast] != 0) // If there is no terminating token found
v.push_back(s.substr(posLast));
return v;
}
Demo with various test cases.