Access elements of boost tokenizer - c++

I'm trying to assign columns of a file using boost to a std::map. I would like to assign element 0 from each line to the index and element 2 to the value. Is there a way to do this without an iterator? The addr_lookup line does not work.
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <boost/tokenizer.hpp>
#include <boost/lexical_cast.hpp>
int main()
{
std::ifstream myfile("core_info_lowbits.tab", std::ios_base::in);
std::string line;
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
boost::char_separator<char> sep(" ");
std::map<std::string, unsigned int> addr_lookup;
while ( std::getline (myfile,line) )
{
tokenizer tokens(line, sep);
//Line below does not work
addr_lookup[*tokens.begin()] = boost::lexical_cast<unsigned int> (*(tokens.begin()+2));
for (tokenizer::iterator tok_iter=tokens.begin();
tok_iter != tokens.end(); ++tok_iter)
std::cout << *tok_iter << std::endl;
}
}

You are trying to advance the iterator using +, which is not possible
Use:
tokenizer::iterator it1,it2= tokens.begin();
it1=it2;
++it2; ++it2;
addr_lookup[*it1] = boost::lexical_cast<unsigned int> (*it2);
Or simply,
tokenizer::iterator it1,it2= tokens.begin();
it1=it2;
std::advance(it2,2);
addr_lookup[*it1] = boost::lexical_cast<unsigned int> (*it2);

Related

Write a bimap to binary file and then read it

I would like to know how to write a bimap which is actually too large( 180 million to 3000 million entries) to a binary file and then read to do some operation. To create a bimap I have the following code, where I created two streams to write and read binary data. I also insert the elements into the bimap.
#include <string>
#include <iostream>
#include <utility>
#include <fstream>
#include <boost/bimap.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <boost/bimap/unordered_multiset_of.hpp>
namespace bimaps = boost::bimaps;
typedef boost::bimap<bimaps::unordered_set_of<unsigned long long int>,
bimaps::unordered_multiset_of<unsigned long long int > > bimap_reference;
typedef bimap_reference::value_type position;
bimap_reference numbers;
int main()
{
std::ofstream outfile ("bmap",std::ofstream::binary);
std::ifstream infile ("bmap",std::ifstream::binary);
numbers.insert(position(123456, 100000));
numbers.insert(position(234567, 80000));
numbers.insert(position(345678, 100000));
numbers.insert(position(456789, 80000));
//want to write the file
//want to read the file
// So that I can perform the following operation
using ritr = bimap_reference::right_const_iterator;
std::pair<ritr, ritr> range = numbers.right.equal_range(80000);
auto itr = range.first;
std::cout<<"first: "<<itr->first<<std::endl;
if(itr != numbers.right.end() && itr->second ==80000){
for (itr = range.first; itr != range.second; ++itr)
{
std::cout<<"numbers:"<<itr->second<<"<->"<<itr->first<<std::endl;
}
}
else {
std::cout<<"Not found:"<<std::endl;
}
return 0;
}
I want to write the bimap, and then read it again to perform some operation. How to do it.
To handle bimap write/read to/from binary file, boost serialization is very helpful. You need to include
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
as header files. Then you need to have file streams for write and read, and use boost::archive::binary_oarchive to write and boost::archive::binary_iarchive to read back. Also make sure you compile the code using -lboost_serialization. The full code is given below.
#include <string>
#include <iostream>
#include <utility>
#include <fstream>
#include <boost/bimap.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <boost/bimap/unordered_multiset_of.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
namespace bimaps = boost::bimaps;
typedef boost::bimap<bimaps::unordered_set_of<unsigned long long int>,
bimaps::unordered_multiset_of<unsigned long long int > > bimap_reference;
typedef bimap_reference::value_type position;
bimap_reference numbers;
int main()
{
// insert elements into bimap and write to a binary file
{
numbers.insert(position(123456, 100000));
numbers.insert(position(234567, 80000));
numbers.insert(position(345678, 100000));
numbers.insert(position(456789, 80000));
std::ofstream ofs("data");
boost::archive::binary_oarchive oa(ofs);
oa << const_cast<const bimap_reference&>(numbers);
const bimap_reference::left_iterator left_iter = numbers.left.find(123456);
oa << left_iter;
const bimap_reference::right_iterator right_iter = numbers.right.find(100000);
oa << right_iter;
}
// load the bimap back to memory
{
std::ifstream ifs("data", std::ios::binary);
boost::archive::binary_iarchive ia(ifs);
ia >> numbers;
assert( numbers.size() == 4 ); // to throw an error
bimap_reference::left_iterator left_iter;
ia >> left_iter;
assert( left_iter->first == 123456 );
bimap_reference::right_iterator right_iter;
ia >> right_iter;
assert( right_iter->first == 100000 );
}
// then perform the following operation
using ritr = bimap_reference::right_const_iterator;
std::pair<ritr, ritr> range = numbers.right.equal_range(80000);
auto itr = range.first;
std::cout<<"first: "<<itr->first<< " <-> " << itr->second<<std::endl;
if(itr != numbers.right.end() && itr->first ==80000){
for (itr = range.first; itr != range.second; ++itr)
{
std::cout<<"numbers:"<<itr->second<<"<->"<<itr->first<<std::endl;
}
}
else {
std::cout<<"Not found:"<<std::endl;
}
return 0;
}

C++, undefined reference to a function that despite including it's header [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 7 years ago.
I'm pretty new to C++, and working through a book called "Accelerated C++." In one of the chapters you are suppose to make a program that, given a string of text, tells you what line(s) each word appears on. To break up all of the words in the string, i used a function called 'split' from a different source file, but included its header file so I could use it. It didn't work though. For the life of me I can't figure out why the linker tells me "undefined reference to 'split(std::string const&)'
split.cpp:
#include <string>
#include <cctype>
#include <vector>
#include "split.h"
using namespace std;
bool space(char c) {
return isspace(c);
}
bool not_space(char c) {
return !isspace(c);
}
vector<string> split(const string& s) {
vector<string> ret;
string::const_iterator i = s.begin();
while (i != s.end()) {
i = find_if(it, s.end(), not_space);
string::const_iterator j = i;
j = find_if(j, s.end(), space);
if (i != s.end())
ret.push_back(string(i, j));
i = j;
}
return ret;
}
split.h:
#ifndef GUARD_split_h
#define GUARD_split_h
#include <string>
#include <vector>
bool space(char);
bool not_space(char);
std::vector<std::string> split(const std::string&);
#endif
Word_Counter.cpp:
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include "split.h"
using namespace std;
map<string, vector<int> > xref(istream& in, vector<string>
find_words(const string&) = split) {
string line;
int line_number = 0;
map<string, vector<int> > ret;
while (getline(in, line)) {
++line_number;
vector<string> words = find_words(line);
for (vector<string>::const_iterator it = words.begin();
it != words.end(); it++)
ret[*it].push_back(line_number);
}
return ret;
}
int main() {
map<string, vector<int> > ret = xref(cin);
for(map<string, vector<int> >::const_iterator it = ret.begin();
it != ret.end(); it++) {
cout << it->first << "occurs on line(s): ";
vector<int>::const_iterator line_it = it->second.begin();
cout << *line_it;
line_it++;
while(line_it != it->second.end()) {
cout << ", " << *line_it;
line_it++;
}
cout << endl;
}
return 0;
}
I've been having a tough time with headers in general lately. Any help is greatly appreciated!
If you have sources split in several files, you need to make the compiler aware of all them. The simplest way is to list all .cpp files (not .h files!) on the command line:
g++ Word_Counter.cpp split.cpp -o Word_Counter

Find values in vector within map< string, <vector<string> > in c++

std::map< std::string, std::vector<std::string> > families;
// add new families
families["Jones"];
families["Smith"];
families["Doe"];
// add children
families["Jones"].push_back( "Jane" );
families["Jones"].push_back( "Jim" );
I added the values to vector within the map using above method. How can I check if "Jane" exists in map with key "Jones"?
Use the find member function of std::map for this and after that a regular string search:
std::map<std::string, std::vector<std::string> >::const_iterator search = families.find("Jones");
if(search != families.end())
{
std::vector<std::string> s = search->second;
if (std::find(s.begin(), s.end(), "Jane") != s.end())
{
}
}
Here's an example:
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
int main()
{
std::map< std::string, std::vector<std::string> > families;
// add new families
families["Jones"];
families["Smith"];
families["Doe"];
// add children
families["Jones"].push_back( "Jane" );
families["Jones"].push_back( "Jim" );
auto family_iterator = families.find("Jones");
if (family_iterator != families.end())
{
const std::vector<std::string>& family = family_iterator->second;
if (std::find(family.begin(), family.end(), "Jane") != family.end())
std::cout << "found\n";
}
}
Basically, families.find() searches in a map and returns an iterator, for which ->first is the key you've found and ->second is the value: your value is the std::vector<std::string> for the "Jones" family, and for convenience/concision I create a const reference to it.
To search in vector I use std::find() from <algorithm>.
Code available/runnable here
Just check if given surname is in your map and then use std::find. I am not using auto, as from the comments I believe you may not be using C++11-compatible compiler.
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
bool exists(std::map<std::string, std::vector<std::string> >& families,
std::string& name, std::string& surname) {
if(families.find(surname) == families.end()) return 0;
std::vector<std::string> names = families[surname];
return std::find(names.begin(), names.end(), name) != names.end();
}
int main(int argc, char* argv[]) {
std::map<std::string, std::vector<std::string> > families;
// add new families
families["Jones"];
families["Smith"];
families["Doe"];
// add children
families["Jones"].push_back("Jane");
families["Jones"].push_back("Jim");
std::string name("Jane"), surname("Jones");
bool ex1 = exists(families, name, surname);
std::cout << ex1 << std::endl;
return 0;
}

Infinite loop on 'getline' in Visual Studio 2010

I am working through some C++ exercises in Visual Studio 2010, and I keep having problems with an infinite loop which occurs when I try to terminate a standard in stream with "CTRL-Z", when using the getline() function. Here is the relevant bit of code....
// find all the lines that refer to each word in the input
map<string, vector<int> >
xref(istream& in,
vector<string> find_words(const string&) = split)
{
string line;
int line_number = 0;
map<string, vector<int> > ret;
// read the next line
while (getline(in, line)) {
++line_number;
// break the input line into words
vector<string> words = find_words(line);
// remember that each word occurs on the current line
for (vector<string>::const_iterator it = words.begin();
it != words.end(); ++it)
ret[*it].push_back(line_number);
}
return ret;
}
...instead of kicking me out of the while loop, the program goes into an infinite loop printing a random integer. I'm pretty sure this is something specific to the Windows environment that I'm missing. Here's the entire code...
#include <algorithm>
#include <cctype>
#include <string>
#include <vector>
#include "split.h"
using std::find_if;
using std::string;
using std::vector;
using std::isspace;
// `true' if the argument is whitespace, `false' otherwise
bool space(char c)
{
return isspace(c);
}
// `false' if the argument is whitespace, `true' otherwise
bool not_space(char c)
{
return !isspace(c);
}
vector<string> split(const string& str)
{
typedef string::const_iterator iter;
vector<string> ret;
iter i = str.begin();
while (i != str.end()) {
// ignore leading blanks
i = find_if(i, str.end(), not_space);
// find end of next word
iter j = find_if(i, str.end(), space);
// copy the characters in `[i,' `j)'
if (i != str.end())
ret.push_back(string(i, j));
i = j;
}
return ret;
}
#include <map>
#include <iostream>
#include <string>
#include <vector>
#include "split.h"
using std::cin; using std::cout;
using std::endl; using std::getline;
using std::istream; using std::string;
using std::vector; using std::map;
// find all the lines that refer to each word in the input
map<string, vector<int> >
xref(istream& in,
vector<string> find_words(const string&) = split)
{
string line;
int line_number = 0;
map<string, vector<int> > ret;
// read the next line
while (getline(in, line)) {
++line_number;
// break the input line into words
vector<string> words = find_words(line);
// remember that each word occurs on the current line
for (vector<string>::const_iterator it = words.begin();
it != words.end(); ++it)
ret[*it].push_back(line_number);
}
return ret;
}
int main()
{
// call `xref' using `split' by default
map<string, vector<int> > ret = xref(cin);
// write the results
for (map<string, vector<int> >::const_iterator it = ret.begin();
it != ret.end(); ++it) {
// write the word
cout << it->first << " occurs on line(s): ";
// followed by one or more line numbers
vector<int>::const_iterator line_it = it->second.begin();
cout << *line_it; // write the first line number
++line_it;
// write the rest of the line numbers, if any
while (line_it != it->second.end()) {
cout << ", " << *line_it;
++line_it;
}
// write a new line to separate each word from the next
cout << endl;
}
return 0;
}
I think instead of trying to make this work, I'd start by writing code I could understand (and for me to understand it, the code has to be fairly simple):
#include <map>
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#include "infix_iterator.h"
typedef std::map<std::string, std::vector<unsigned> > index;
namespace std {
ostream &operator<<(ostream &os, index::value_type const &i) {
os << i.first << ":\t";
std::copy(i.second.begin(), i.second.end(),
infix_ostream_iterator<unsigned>(os, ", "));
return os;
}
}
void add_words(std::string const &line, size_t num, index &i) {
std::istringstream is(line);
std::string temp;
while (is >> temp)
i[temp].push_back(num);
}
int main() {
index i;
std::string line;
size_t line_number = 0;
while (std::getline(std::cin, line))
add_words(line, ++line_number, i);
std::copy(i.begin(), i.end(),
std::ostream_iterator<index::value_type>(std::cout, "\n"));
return 0;
}
As (more or less) usual, this needs the infix_ostream_iterator I've posted elsewhere.

How to erase a line using the condition?

I've a string (ifstream) with next lines:
foo
foo+..
foo
And, I'd like know how to get the line where there is a symbol + and erase the remaining lines:
foo+..
to convert the stream into a string, I use:
string stream((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
How about this alternative solution:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
bool HasNoPlus(const string &value)
{
return value.find('+') == string::npos;
}
int main(int argc, char* argv[])
{
ifstream ifs("d:\\temp\\test.txt");
vector<string> out;
remove_copy_if(istream_iterator<string>(ifs),
istream_iterator<string>(),
back_inserter(out),
HasNoPlus);
return 0;
}
If you don't need the intermediate string, you can copy from ifstream directly to a new ofstream, using standard algorithms:
#include <algorithm>
#include <fstream>
#include <iterator>
#include <string>
struct has_no_plus {
bool operator()(const std::string& str)
{
if (str.find('+') != std::string::npos)
return false;
else
return true;
}
};
int main()
{
std::ifstream ifs("file.txt");
std::ofstream ofs("copy.txt");
std::remove_copy_if(std::istream_iterator<std::string>(ifs),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(ofs, "\n"),
has_no_plus());
// or alternatively, in C++11:
std::copy_if(std::istream_iterator<std::string>(ifs),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(ofs, "\n"),
[](const std::string& str)
{
return str.find('+') != str.npos;
});
}
int pos_plus = str.find('+');
int pos_beg = str.find_last_of('\n',pos_plus);
int pos_end = str.find_first_of('\n',pos_plus);
if(pos_beg == pos_plus) pos_beg = 0;
if(pos_end == pos_plus) pos_end = str.size();
str.erase(pos_beg,pos_end-pos_beg);
To filter input from ifstream (as mentioned in your comment), use a new ostringstream.
Read every line from ifstream (getline) and check whether it passes the filter condition.
If it passes, append it to the ostringstream.
When you take the string from the ostringstream, you will have the filtered string.