Related
I need help fixing the following code, it is a c++ whitespace detector that uses different words to produce different outputs:
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
using namespace std;
string Line;
string firstWord[99];
string secondWord[99];
int lineFunction(string line) {
string line[199];
for (int i = 0; i < line.length(); i++) {
while (isspace(line[i]) == false) {
firstWord += line[i];
}
secondWord += line[i];
}
}
int main() {
cin >> Line;
lineFunction(Line);
if (firstWord == "A") {
if (secondWord == "B") {
cout << "AB";
}
}
}
The expected result when I input A B (with a space) should be the letters AB (without a space, to test how it works) printed onto the screen, as a result of the if statements, but I am trying to make the output configurable. The errors that I receive when I try to run this are:
main.cpp: In function ‘int lineFunction(std::string)’:
main.cpp:12:20: error: declaration of ‘std::string line [199]’ shadows a parameter
string line[199];
^
main.cpp:13:30: error: request for member ‘length’ in ‘line’, which is of non-class type ‘std::string [199] {aka std::basic_string [199]}’
for (int i = 0; i < line.length(); i++) {
^~~~~~
main.cpp:14:31: error: no matching function for call to ‘isspace(std::string&)’
while (isspace(line[i]) == false) {
^
In file included from /usr/include/c++/6/cctype:42:0,
from main.cpp:2:
/usr/include/ctype.h:118:1: note: candidate: int isspace(int)
__exctype (isspace);
^
/usr/include/ctype.h:118:1: note: no known conversion for argument 1 from ‘std::string {aka std::basic_string}’ to ‘int’
In file included from /usr/include/c++/6/bits/basic_ios.h:37:0,
from /usr/include/c++/6/ios:44,
from /usr/include/c++/6/ostream:38,
from /usr/include/c++/6/iostream:39,
from main.cpp:3:
/usr/include/c++/6/bits/locale_facets.h:2565:5: note: candidate: template bool std::isspace(_CharT, const std::locale&)
isspace(_CharT __c, const locale& __loc)
^~~~~~~
/usr/include/c++/6/bits/locale_facets.h:2565:5: note: template argument deduction/substitution failed:
main.cpp:14:31: note: candidate expects 2 arguments, 1 provided
while (isspace(line[i]) == false) {
^
main.cpp:15:23: error: no match for ‘operator+=’ (operand types are ‘std::string [99] {aka std::basic_string [99]}’ and ‘std::string {aka std::basic_string}’)
firstWord += line[i];
~~~~~~~~~~^~~~~~~~~~
main.cpp:17:20: error: no match for ‘operator+=’ (operand types are ‘std::string [99] {aka std::basic_string [99]}’ and ‘std::string {aka std::basic_string}’)
secondWord += line[i];
~~~~~~~~~~~^~~~~~~~~~
main.cpp: In function ‘int main()’:
main.cpp:24:22: error: comparison between distinct pointer types ‘std::string* {aka std::basic_string*}’ and ‘const char*’ lacks a cast [-fpermissive]
if (firstWord == "A") {
^~~
main.cpp:25:27: error: comparison between distinct pointer types ‘std::string* {aka std::basic_string*}’ and ‘const char*’ lacks a cast [-fpermissive]
if (secondWord == "B") {
Here are some possible solutions to fix the errors.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
// don't use
// using namespace std;
// don't use global variables
// string Line;
// string firstWord[99]; you need strings, not arrays
// string secondWord[99];
// use references to return multiple values and no return value
// alternatively you could return a std::pair
void lineFunction(std::string line, std::string &firstWord, std::string &secondWord) {
// string line[199]; you don't need this variable
// line.length() return unsigned int so you should compare with unsigned int
// this whole loop makes no sense
// for (unsigned int i = 0; i < line.length(); i++) {
// this would result in a infinite loop
// while (isspace(line[i]) == false) {
// if (!std::isspace(line[i])) {
// firstWord += line[i];
// }
// secondWord += line[i];
// }
unsigned int i;
for (i = 0; i < line.length() && !std::isspace(line[i]); ++i) {
firstWord += line[i];
}
for (++i; i < line.length(); ++i) {
secondWord += line[i];
}
}
int main() {
std::string line;
// std::cin only reads until first whitespace
// std::cin >> line;
std::getline(std::cin, line);
std::string firstWord;
std::string secondWord;
lineFunction(line, firstWord, secondWord);
if (firstWord == "A" && secondWord == "B") {
std::cout << "AB";
}
}
I am trying to debug this code from my supervisor and I'm new to C++.
I found a few similar no matching function for call to questions, which gave me ideas what the problem might be but was not able to solve it.
I have listed my thoughts below the error message and relevant function.
Error message:
In function ‘int main(int, char**)’:
distanceMatrixToSageGraph.c:104:43: error: no matching function for call to
‘std::vector<std::vector<int>>::push_back(std::vector<std::__cxx11::basic_string<char> >&)’
the_entries.push_back( row_as_vector );
Relevant function:
int main(int argc, char** threshold_and_distanceMatrixfilename)
{
if (argc < 2 || argc > 2)
{
std::cerr << "Usage: ./distanceMatrixToSageGraph.o <threshold>
<distanceMatrix_file_calculated_fromDGEsingleCell_data>" << std::endl;
return -1;
}
string distanceMatrixfilename = threshold_and_distanceMatrixfilename[2];
int threshold = std::stoi(threshold_and_distanceMatrixfilename[1]);
std::ifstream distanceMatrixFile(distanceMatrixfilename);
if (!distanceMatrixFile)
{
std::cerr << "Error opening distanceMatrix file: " << distanceMatrixfilename << std::endl;
return -1;
}
string row;
std::getline(distanceMatrixFile, row); // discard the first row, which specifies the format of the file.
vector<vector<int>> the_entries;
while (std::getline(distanceMatrixFile, row))
{
std::stringstream row_as_stringstream(row);
int i; i = 0;
vector<string> row_as_vector;
while (row_as_stringstream.good())
{
string substr;
getline(row_as_stringstream, substr, ',');
row_as_vector.push_back(substr);
};
the_entries.push_back(row_as_vector); //LINE 104
};
}
Ideas:
It would be great if someone could explain to me: std::vector<std::vector<int>>::push_back(std::vector<std::__cxx11::basic_string<char>>&)
I understand that std::vector<std::vector<int>> is a matrix and
that push_back adds an element at the end of the vector.
I suspect that we're trying to read in the wrong type in
the_entries.push-back(row_as_vector).
The original code took a csv file as input, containing integers
and strings. Now we're reading in a txt file having the shape:
TEXT
0; INT; INT; INT; INT; ...
0; INT; INT; INT; INT; ...
18 more lines of the above numbers and semicolons
In the above, we remove the first row in line 89.
Is it possible the code has to be changed much more to be able to
read this txt file instead of the csv file?
Rest of error message:
In file included from /usr/include/c++/6/vector:64:0,
from distanceMatrixToSageGraph.c:13:
/usr/include/c++/6/bits/stl_vector.h:914:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::vector<int>; _Alloc = std::allocator<std::vector<int> >; std::vector<_Tp, _Alloc>::value_type = std::vector<int>]
push_back(const value_type& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:914:7: note: no known conversion for argument 1 from ‘std::vector<std::__cxx11::basic_string<char> >’ to ‘const value_type& {aka const std::vector<int>&}’
/usr/include/c++/6/bits/stl_vector.h:932:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = std::vector<int>; _Alloc = std::allocator<std::vector<int> >; std::vector<_Tp, _Alloc>::value_type = std::vector<int>]
push_back(value_type&& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:932:7: note: no known conversion for argument 1 from ‘std::vector<std::__cxx11::basic_string<char> >’ to ‘std::vector<std::vector<int> >::value_type&& {aka std::vector<int>&&}’
Whole code:
// Convert distanceMatrix tables of protein interactions to SAGE graph.
///////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <fstream>
#include <sstream>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <list>
#include <vector>
#include <tuple>
#include <algorithm>
using namespace std;
void writeGraphInSageFormat(string name, std::vector<std::vector<int>> TheEdges)
{
//////////////////////////////////////////////////////////////////////////////////////
// Write out the edges in SAGE format.
///////////////////////////////////////////////////////////////////////////////////////
int edgeNumber = TheEdges.size();
ofstream d1sageFile(name, ios::out);
d1sageFile << "g = Graph([" << endl;
for (int n = 0; n < edgeNumber; n++) {
d1sageFile << "(" << TheEdges[n][0] + 1 << "," << TheEdges[n][1] + 1 << ")," << endl;
}
d1sageFile << "])" << endl;
d1sageFile << "g.show()" << endl;
d1sageFile.close();
std::cout << "SAGE graph written into the file " << name << std::endl;
}
std::vector<std::vector<int>> ConvertEntriesMatrixToEdges(vector<vector<int>> the_entries, int threshold)
{
////////////////////////////////////////////////////////////////////////////////////////////
// Construct the edge-vertex incidence matrix (d_1) from the distanceMatrix entries matrix:
////////////////////////////////////////////////////////////////////////////////////////////
std::vector<std::string> proteinNames;
std::vector<std::vector<int>> TheEdges;
std::cout << "Registering only edges shorter than " << threshold << "." << std::endl;
int thisDistance;
for (int i = 0; i < the_entries.size(); i++)
{
for (int j = i + 1; j < the_entries.size(); j++)
{
// we could use the_entries.size() instead of the_entries.at(i).size(), because this is a square matrix.
thisDistance = the_entries.at(i).at(j);
if (thisDistance < threshold)
{
std::vector<int> CurrentEdge(2);
CurrentEdge[0] = i;
CurrentEdge[1] = j;
TheEdges.push_back(CurrentEdge);
};
};
};
return TheEdges;
}
///////////////////////////////////////////
// Main Program: Extract edges from a distanceMatrix file.
///////////////////////////////////////////
int main(int argc, char** threshold_and_distanceMatrixfilename)
{
if (argc < 2 || argc > 2)
{
std::cerr << "Usage: ./distanceMatrixToSageGraph.o <threshold> <distanceMatrix_file_calculated_fromDGEsingleCell_data>" << std::endl;
return -1;
}
string distanceMatrixfilename = threshold_and_distanceMatrixfilename[2];
int threshold = std::stoi(threshold_and_distanceMatrixfilename[1]);
std::ifstream distanceMatrixFile(distanceMatrixfilename);
if (!distanceMatrixFile) {
std::cerr << "Error opening distanceMatrix file: " << distanceMatrixfilename << std::endl;
return -1;
}
string row; //LINE 88
std::getline(distanceMatrixFile, row); // discard the first row, which specifies the format of the file.
vector<vector<int>> the_entries;
while (std::getline(distanceMatrixFile, row))
{
std::stringstream row_as_stringstream(row);
int i; i = 0;
vector<string> row_as_vector;
while (row_as_stringstream.good())
{
string substr;
getline(row_as_stringstream, substr, ',');
row_as_vector.push_back(substr);
};
the_entries.push_back(row_as_vector); //LINE 104
};
////////////////////////////////////////////////////////////
// Now we assemble the entries to an edges matrix, and write it into a Sage file:
////////////////////////////////////////////////////////////
std::vector<std::vector<int>> TheEdges = ConvertEntriesMatrixToEdges(the_entries, threshold);
char outputFilename[60]; strcpy(outputFilename, distanceMatrixfilename.c_str()); strcat(outputFilename, "AtThreshold"); string thrshld = std::to_string(threshold); strcat(outputFilename, thrshld.c_str()); strcat(outputFilename, ".txt");
writeGraphInSageFormat(outputFilename, TheEdges);
return 0;
}
I suspect that we're trying to read in the wrong type in
the_entries.push-back(row_as_vector)
error: no matching function for call to
‘std::vector<std::vector<int>>::push_back(std::vector<std::__cxx11::basic_string<char> >&)’
the_entries.push_back( row_as_vector );
Yes, your right about this. The error message says that you are trying to push back a vector of strings to a vector of vector of integers. They are entirely different types and hence not possible.
You probably want to either change the type of the_entries to
std::vector<std::vector<std::string>> the_entries;
// ^^^^^^^^^^^^
or
convert the strings to integers using std::stoi while pushing back to the std::vector<int> row_as_vector.
std::vector<int> row_as_vector;
while(row_as_stringstream.good())
{
// ......
row_as_vector.push_back(std::stoi(substr));
// ^^^^^^^^^^^^^^^^^^^
};
the_entries.push_back( row_as_vector );
Is it possible the code has to be changed much more to be able to read
this txt file instead of the csv file?
If the contents of those two are same, you don't need to make much difference in your code. However, ; should be parsed out before calling std::stoi to them. Because it may through invalid_argument exception for the bad argument.
A few suggestions:
Consider not to practice with using namespace std;. See this post
for more:
Why is "using namespace std;" considered bad practice?
When you pass the non-primitive types(i.e. std::string,
std::vector.. etc) to the function, consider the case, if the
parameters are read-only or not. If the data should be modified
pass-by-ref and if read-only(no modification should have been made inside the function) pass them by const-ref. Read more:
How to pass objects to functions in C++?
I wrote a program in c++ which is supposed to print how many time a certain letter is contained in a word. So I used a 2-D arrays which is kinda new to me, i get 3 error codes which I don't really understand. Thanks for your help!
#include <iostream>
#include <cstring>
void check(char wArr[], int letter[], char search[], std::string word);
int main(int argc, char const *argv[]) {
//int letter[26] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
char search[26][2] = {{'a', 0},{'b', 0},{'c', 0},{'d', 0},{'e', 0},{'f', 0},{'g', 0},{'h', 0} ,{'i', 0} ,
{'j', 0},{'k', 0},{'l', 0},{'m',0} ,{'n',0} ,{'o',0},{'p',0},{'q',0},{'r',0},{'s',0},{'t',0},
{'u', 0},{'v', 0} ,{'w',0},{'x',0},{'y', 0},{'z', 0}};
std::string word;
std::cout << "Please enter the word: \n";
std::cin >> word;
char wArr[word.length()];
strcpy (wArr, word.c_str ());
check(wArr, search, word);
return 0;
}
void check(char wArr, char search[][2], std::string word){
for(int s = 0; s < 26; s++) {
for ( char i = 0; i < word.length(); i++) {
if(wArr[i] == search[s][1]) {
search[s][2]++;
}
}
}
for (int t = 0; t < 26; t++) {
if(search[t][2] > 0){
std::cout << search[t][1] << ": " << search[t][2] << '\n';
}
}
}
Error codes:
/home/julian/workspace-atom/countletter/main.cpp: In function ‘int main(int, const char**)’:
/home/julian/workspace-atom/countletter/main.cpp:16:33: error: cannot convert ‘char (*)[2]’ to ‘int*’ for argument ‘2’ to ‘void check(char*, int*, char*, std::__cxx11::string)’
check(wArr, search, word);
^
/home/julian/workspace-atom/countletter/main.cpp: In function ‘void check(char, char (*)[2], std::__cxx11::string)’:
/home/julian/workspace-atom/countletter/main.cpp:24:34: error: invalid types ‘char[char]’ for array subscript
if(wArr[i] == search[s][1]) {
^
The error is pretty clear. Your function prototype has different types for arguments compared to the actual definition:
void check(char wArr[], int letter[], char search[], std::string word);
vs
void check(char wArr, char search[][2], std::string word)
The second error is due to an attempt to use wArr as an array while it's been declared as char.
My program takes two input files, one of which is a list of commands. Each line of the file is a new command, so i want to parse this file into an array. I was told to use a vector as it dynamically grows which would eliminate the need for a function to count the number of lines in the file and then use that data to create an array.
Here is what my program is right now:
#include<iostream>
#include<string>
#include<fstream>
#include<vector>
using namespace std;
//Prototypes
int parseLines(ifstream& countfile);
vector<string> parseLines(ifstream& countfile)
//counts number of lines in file passed to function
{
string line;
vector<string> lines;
int numberOfLines;
//reads through each line until end of file putting each line in a sperate entry of the vector
while(getline(countfile, line))
{
lines.push_back(line);
}
return lines;
}
int main (int argc, char* argv[])
{
int i;
if(argc != 3) cout << "Usage: calendar.out datafile inputfile";
//Create input streams to both files
ifstream apptsfp;
ifstream inputfp;
//Open streams to both files
apptsfp.open(argv[1]);
inputfp.open(argv[2]);
if(!inputfp.is_open())
{
cerr << "failed to open input file\n";
return 1;
}
vector<string> inputVector;
vector<string> apptsVector;
inputVector = parseLines(inputfp);
for(i=0; i<= inputVector.size(); i++)
{
cout << "Input " << i << ": " << inputVector[i] << endl;
}
return 0;
}
And i am getting this long error when i compile and i dont quite understand it:
$ g++ calendar.cpp
calendar.cpp: In function ‘std::vector<std::basic_string<char> > parseLines(std::ifstream&)’:
calendar.cpp:17:46: error: new declaration ‘std::vector<std::basic_string<char> > parseLines(std::ifstream&)’
calendar.cpp:14:5: error: ambiguates old declaration ‘int parseLines(std::ifstream&)’
calendar.cpp: In function ‘int main(int, char**)’:
calendar.cpp:58:37: error: no match for ‘operator=’ in ‘inputVector = parseLines((* & inputfp))’
calendar.cpp:58:37: note: candidate is:
In file included from /usr/include/c++/4.7/vector:70:0,
from calendar.cpp:9:
/usr/include/c++/4.7/bits/vector.tcc:161:5: note: std::vector<_Tp, _Alloc>& std::vector<_Tp, _Alloc>::operator=(const std::vector<_Tp, _Alloc>&) [with _Tp = std::basic_string<char>; _Alloc = std::allocator<std::basic_string<char> >]
/usr/include/c++/4.7/bits/vector.tcc:161:5: note: no known conversion for argument 1 from ‘int’ to ‘const std::vector<std::basic_string<char> >&’
I feel like i don't quite understand how to use vectors.
Prototype
int parseLines(ifstream& countfile);
Realization
vector<string> parseLines(ifstream& countfile)
Return types differs.
Not the question asked but another error is
for (i = 0; i <= inputVector.size(); i++)
should be
for (i = 0; i < inputVector.size(); i++)
The problem is in int parseLines(ifstream& countfile); function declaration. There is a conflict with later vector<string> parseLines(ifstream& countfile) definition:
Change first with:
vector<string> parseLines(ifstream& countfile);
Besides, as this function definition is before its use, you can delete its declaration.
For my computer science class, we need to write a program (in C++) that takes an input of characters and outputs the possible permutations of it according to the dial pad on a phone, leaving non-digit characters in place.
For example, inputing 2 outputs 2, A, B, C. Inputing 23 outputs 23, A3, B3, C3, 2D, 2E, 2F, AD, AE, AF, BD, BE, BF, etc...
The application provided for this program is finding permutations of "vanity" phone numbers for a given phone number.
Currently, the program I have written doesn't even compile, and I'm afraid the algorithm I'm using is incorrect:
#include <iostream>
#include <multimap.h>
#include <vector>
using namespace std;
// Prototypes
void initLetterMap(multimap<char,char> &lmap);
void showPermutations(const vector<string> &perms);
vector<string> getPermutations(const string &phoneNumber,const multimap<char,char> &lmap);
vector<char> getLetters(char digit, const multimap<char,char> &lmap);
// Declarations
void initLetterMap(multimap<char,char> &lmap) {
lmap.insert(pair<char,char>('1','1'));
lmap.insert(pair<char,char>('2','2'));
lmap.insert(pair<char,char>('2','A'));
lmap.insert(pair<char,char>('2','B'));
lmap.insert(pair<char,char>('2','C'));
lmap.insert(pair<char,char>('3','3'));
lmap.insert(pair<char,char>('3','D'));
lmap.insert(pair<char,char>('3','E'));
lmap.insert(pair<char,char>('3','F'));
// ...
}
vector<char> getLetters(char digit, const multimap<char,char> &lmap) {
multimap<char,char>::iterator it;
pair<multimap<char,char>::iterator,multimap<char,char>::iterator> range;
vector<char> result;
if (isdigit(digit)) {
range = lmap.equal_range(digit);
for (it=range.first;it!=range.second;++it) {
result.push_back((*it).second);
}
} else {
result.insert(result.end(),digit);
}
return result;
}
void showPermutations(vector<string> &perms) {
vector<string>::iterator it;
for (it = perms.begin(); it != perms.end(); it++) {
cout << *it << endl;
}
}
vector<string> getPermutations(const string &phoneNumber,const multimap<char,char> &lmap) {
vector<string> results;
string number = phoneNumber;
vector<char>::iterator vcit;
vector<char> letters;
unsigned int i;
for (i=0;i<phoneNumber.length();i++) {
letters = getLetters(number[i],lmap);
for (vcit=letters.begin();vcit!=letters.end();vcit++) {
number[i] = *vcit;
results.push_back(number);
}
}
return results;
}
int main() {
multimap<char,char> lmap;
initLetterMap(lmap);
string input;
cout << "Enter a phone number to get all possible vanity numbers" << endl;
cout << "> "; getline(cin,input);
showPermutations(getPermutations(input,lmap));
return 0;
}
I get a whole slew of build issues when I try to build this, and am not sure how to resolve most of them:
In file included from /usr/include/c++/4.0.0/backward/multimap.h:59,
from phone02.cpp:18:
/usr/include/c++/4.0.0/backward/backward_warning.h:32:2: warning: #warning This file includes at least one deprecated or antiquated header. Please consider using one of the 32 headers found in section 17.4.1.2 of the C++ standard. Examples include substituting the <X> header for the <X.h> header for C++ includes, or <iostream> instead of the deprecated header <iostream.h>. To disable this warning use -Wno-deprecated.
/usr/include/c++/4.0.0/bits/stl_pair.h: In constructor 'std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&) [with _U1 = std::_Rb_tree_const_iterator<std::pair<const char, char> >, _U2 = std::_Rb_tree_const_iterator<std::pair<const char, char> >, _T1 = std::_Rb_tree_iterator<std::pair<const char, char> >, _T2 = std::_Rb_tree_iterator<std::pair<const char, char> >]':
phone02.cpp:75: instantiated from here
/usr/include/c++/4.0.0/bits/stl_pair.h:90: error: no matching function for call to 'std::_Rb_tree_iterator<std::pair<const char, char> >::_Rb_tree_iterator(const std::_Rb_tree_const_iterator<std::pair<const char, char> >&)'
/usr/include/c++/4.0.0/bits/stl_tree.h:167: note: candidates are: std::_Rb_tree_iterator<_Tp>::_Rb_tree_iterator(std::_Rb_tree_node<_Tp>*) [with _Tp = std::pair<const char, char>]
/usr/include/c++/4.0.0/bits/stl_tree.h:164: note: std::_Rb_tree_iterator<_Tp>::_Rb_tree_iterator() [with _Tp = std::pair<const char, char>]
/usr/include/c++/4.0.0/bits/stl_tree.h:152: note: std::_Rb_tree_iterator<std::pair<const char, char> >::_Rb_tree_iterator(const std::_Rb_tree_iterator<std::pair<const char, char> >&)
/usr/include/c++/4.0.0/bits/stl_pair.h:90: error: no matching function for call to 'std::_Rb_tree_iterator<std::pair<const char, char> >::_Rb_tree_iterator(const std::_Rb_tree_const_iterator<std::pair<const char, char> >&)'
/usr/include/c++/4.0.0/bits/stl_tree.h:167: note: candidates are: std::_Rb_tree_iterator<_Tp>::_Rb_tree_iterator(std::_Rb_tree_node<_Tp>*) [with _Tp = std::pair<const char, char>]
/usr/include/c++/4.0.0/bits/stl_tree.h:164: note: std::_Rb_tree_iterator<_Tp>::_Rb_tree_iterator() [with _Tp = std::pair<const char, char>]
/usr/include/c++/4.0.0/bits/stl_tree.h:152: note: std::_Rb_tree_iterator<std::pair<const char, char> >::_Rb_tree_iterator(const std::_Rb_tree_iterator<std::pair<const char, char> >&)
make: *** [phone02.o] Error 1
The line numbers are a bit off, but the important ones that I can see are the two about no matching function for call to 'std::_Rb_tree_iterator<std::pair<const char, char> >::_Rb_tree_iterator(const std::_Rb_tree_const_iterator<std::pair<const char, char> >&)'
Besides the errors, I also believe I am heading in the wrong direction with my algorithm.
So I have 2 questions here:
Why am I getting these build errors, and how do I fix them?
How would you suggest going about solving this problem? Am I on the right track or no?
For question #2, I would prefer to not get solutions, just advice or pointers in the right direction.
Thanks!
PS: I am building this on Mac OS X 10.5.8 with gcc, using QtCreator 1.2.1
UPDATE:
I have successfully compiled a solution program. I will post the source code to those who are curious.
#include <iostream>
#include <map>
#include <vector>
#include <string>
using namespace std;
void initLetterMap(map<char,string> &lmap);
vector<string> getMapped(const string &phoneNumber, map<char,string> &lmap);
vector<string> getPermutations(vector<string> number);
unsigned long int countPermutations(vector<string> number);
void initLetterMap(map<char,string> &lmap) {
lmap['0'] = "0";
lmap['1'] = "1";
lmap['2'] = "2ABC";
lmap['3'] = "3DEF";
lmap['4'] = "4GHI";
lmap['5'] = "5JKL";
lmap['6'] = "6MNO";
lmap['7'] = "7PQRS";
lmap['8'] = "8TUV";
lmap['9'] = "9WXYZ";
}
unsigned long int countPermutations(vector<string> number) {
long int fold = 1;
int vals = 0;
vector<string>::iterator it;
for (it=number.begin();it!=number.end();it++) {
vals = (*it).length();
fold *= vals;
}
return fold;
}
vector<string> getMapped(const string &phoneNumber, map<char,string> &lmap) {
unsigned int i;
vector<string> out;
char digit;
string temp;
for (i=0;i<phoneNumber.length();i++) {
digit = phoneNumber.at(i);
if (isdigit(digit)) {
out.push_back(lmap[digit]);
} else {
temp = string(1,digit);
out.push_back(temp);
}
}
return out;
}
vector<string> getPermutations(vector<string> number) {
vector<string> results;
unsigned long int i,j,k;
unsigned long int perms = countPermutations(number);
vector<string>::reverse_iterator numit;
string temp,temp2;
vector<int> state = vector<int>(number.size(), 0);
vector<int>::reverse_iterator stateit;
for (i=0;i<perms;i++) {
j=i;
temp = "";
for (stateit=state.rbegin(), numit=number.rbegin();stateit!=state.rend();stateit++, numit++) {
*stateit = j % (*numit).length();
j /= (*numit).length();
temp.insert(temp.begin(),(*numit)[*stateit]);
}
results.push_back(temp);
}
return results;
}
int main() {
map<char,string> lettermap;
initLetterMap(lettermap);
string input;
cout << "> "; getline(cin,input);
vector<string> perms = getPermutations(getMapped(input,lettermap));
vector<string>::iterator it;
for (it=perms.begin();it!=perms.end();it++) {
cout << *it << endl;
}
}
The code is probably more complicated than it has to be, but my goal was to just get it to work. It seems to run fairly quickly for 10 digit phone numbers, so I guess it's not too bad.
Thanks to Jacob and ShreevatsaR for getting me pointed in the right direction!
How about the following:
#include <cstddef>
#include <iostream>
#include <iterator>
#include <string>
#include <algorithm>
template <typename Iterator>
bool next_combination(const Iterator first, Iterator k, const Iterator last);
int main()
{
std::string phone_number = "23";
std::string number[] = {
"0", "1", "2abc", "3def", "4ghi",
"5jkl","6mno", "7pqrs", "8tuv","9wxyz"
};
std::string tmp_set;
std::string set;
for(std::size_t i = 0; i < phone_number.size(); ++i)
{
tmp_set += number[static_cast<std::size_t>(phone_number[i] - '0')];
}
std::sort(tmp_set.begin(),tmp_set.end());
std::unique_copy(tmp_set.begin(),
tmp_set.end(),
std::back_inserter(set));
std::string current_set;
current_set.reserve(phone_number.size());
do
{
std::copy(set.begin(),
set.begin() + phone_number.size(),
std::back_inserter(current_set));
do
{
std::cout << current_set << std::endl;
}
while (std::next_permutation(current_set.begin(),current_set.end()));
current_set.clear();
}
while(next_combination(set.begin(),
set.begin() + phone_number.size(),
set.end()));
return 0;
}
template <typename Iterator>
inline bool next_combination(const Iterator first, Iterator k, const Iterator last)
{
/* Credits: Thomas Draper */
if ((first == last) || (first == k) || (last == k))
return false;
Iterator itr1 = first;
Iterator itr2 = last;
++itr1;
if (last == itr1)
return false;
itr1 = last;
--itr1;
itr1 = k;
--itr2;
while (first != itr1)
{
if (*--itr1 < *itr2)
{
Iterator j = k;
while (!(*itr1 < *j)) ++j;
std::iter_swap(itr1,j);
++itr1;
++j;
itr2 = k;
std::rotate(itr1,j,last);
while (last != j)
{
++j;
++itr2;
}
std::rotate(k,itr2,last);
return true;
}
}
std::rotate(first,k,last);
return false;
}
Well if you don't want a solution, I would implement it like this:
Use a vector V with each element drawn from a string. E.g. if it's 23, then your vector V, would have two vectors each containing 2ABC and 3DEF.
Iterate each digit like a counter through the associated string. Move right-to-left and when each digit overflows increment the one to the left, and reset, etc.
Display the counter at every iteration to obtain your "number".
Hint to compile errors:
there is no file called <multimap.h> in STL. it should be <map>
The problem is with getLetters function. multimap lmap has been passed by const reference. Hence, equal_range API on lmap would return pair of const_iterator not just iterator.
Below code demonstrate how to do it in simple steps(Recursively):
1.) Create vector of strings, and push strings which represents "possible characters resulting from that keypress" (0-key to 9-key).
2.) Since each keypress will serve to add ONLY one char to the resultant string, append only one character at a time and call the function recursively for the next keypress. Do it for each possible char at that keypress.
Demo:
void getCombination(vector<string> &combinations, string current, const string &A, int idx, const vector<string> &keyset){
if(idx >= A.size()) {
combinations.push_back(current);
return;
}
int key = (A[idx] - '0');
int len = keyset[key].length();
for( int i = 0; i < len; i++ ){
current.push_back(keyset[key][i]); //pick at once one char corresp. to that keypress
getCombination(combinations, current, A, idx+1, keyset);
current.pop_back();
}
}
vector<string> letterCombinations(string A) {
vector<string> combinations;
vector<string> keyset{"0", "1", "2abc", "3def", "4ghi", "5jkl", "6mno", "7pqrs", "8tuv", "9wxyz"};
getCombination(combinations, std::string({}), A, 0, keyset);
return combinations;
}
int main() {
vector<string> combinations = letterCombinations("23");
for(string word : combinations){
cout << word << ", ";
}
return 0;
}
Gives Output :
23, 2d, 2e, 2f, a3, ad, ae, af, b3, bd, be, bf, c3, cd, ce, cf,