Assign values based on variable name in a string - c++

Weird question and hard to word but lets say I have a 2 files that have a string of what double variables will appear in the file at the top and then the corresponding double variables, something like:
File1 =
A B C D E
1.2 3.4 4.5 5.6 7.8
File2=
B D E
9.8 7.6 5.4
and I have a struct of doubles
struct numb{
double A,B,C,D,E};
is it possible to read in the string in file 1 (A B C D E) and whatever the first value in the string is (A) assign it to the corresponding struct value numb.A.
So then the next file it will read in the first value of the string (B) and assign it to numb.B.
I realize this is possible with a bunch of if statements but I was wondering if there is an easier way. The hardest part is the string of variables will always be some combination of A,B,C,D,E. I am programming in C++ VS10

You can create a map with the string to parse as the key, and a pointer to member of the corresponding attribute of your structure as the value.
std::map<std::string, double numb::*> mapLetterToCorrespondingAttribute;
Then parse your file and assign the value to the corresponding member pointed to by the value in your map corresponding to the key being the letter you parsed.
Read this multiple times before you say you don't understand :D

A switch is probably the easiest way to do this.
void set_member(numb &n, char member, double value)
{
switch (member) {
case 'A':
n.A = value;
break;
case 'B':
n.B = value;
break;
// etc.
default:
// handle error
}
}

Declare an array of double in struct numb.
struct numb {
void setValue(char label, double val) { value[label-'A'] = val; }
double getValue(char label) const { return value[label-'A']; }
double value[5];
};
Then, you could perform:
numb n;
n.setValue('A', 1.2);
double A = n.getValue('A');

Read the two lines into std::vector<std::string> and then put them into a map in pairs:
std::vector<std::string> vars; // the split up first line
std::vector<std::string> values; // split up second line
std::map<std::string, double> mapping;
for (int i = 0; i < vars.size(); ++i) {
mapping.insert(std::make_pair(vars[i], boost::lexical_cast<double>(values[i]));
}
If you pre-populate the map mapping with sensible default values, this should be quite simple. Also, you can substitute the call to boost::lexical_cast<double> with any conversion method you like.

Related

Compare variables from map with vector in c++

So, I have an input
x=20
y=40
z=x+y
w=20+40+80
s1="str1"
s2=s1+w
I store variables without operators in a map as the variable name and its type like x int, y int, and etc.
map <string,string> finalMap
I split variables of each line into a vector of string for each line as tokens = {20,40,80}; tokens = {s1,w}, and etc.
vector<string> tokens;
I want to compare variables in tokens and finalMap, if I have already declared a variable of tokens in the map. For example z=x+y, x and y already declared in finalMap, I want to check if those x and y already declared in finalMap to get their dataType string or int. I use double for loop, but it doesn't work for some reason.
for(auto i=finalMap.begin(); i!=finalMap.end();i++){
for(int j=0; j<tokens.size(); j++){
if(i->first==tokens.at(j)){
tokens.at(j)==i->second;
}
}
}
I have trouble with the for loop above because when I check values after, it appears that it doesn't replace dataType from map.
for(int i=0; i<tokens.size()-1; i++){
if(checkType(tokens.at(i))!=checkType(tokens.at(i+1)))
return "undefined";
else
return checkType(tokens.at(i));
}
checkType() returns variable type of string, either it is string, int, or list. Please don't downgrade I am a new user if you need more details just let me know I will explain.
Here is the output:
s1:str
s2:undefined
w:int
x:int
y:int
z:undefined
Double equals == is comparison and not assignment.
if(i->first==tokens.at(j)) {
tokens.at(j) == i->second;
}
You meant to use single equals =
if(i->first==tokens.at(j)) {
tokens.at(j) = i->second;
}

c++: Run a function 8 times and add each answer to an array or JSON it

I'm super new to C++ and am trying to build a json file that contains x0...x7 of the files that gets parsed from a pre-defined function so that it can compose a JSON string to give to R. so that it can open a socket to R and send this piece of JSON to it.
however, im kinda stuck here, here is what i have:
std::map<std::string,std::string>::const_iterator qIter;
std::string variable;
std::map<string,string> mymap;
variable = "x";
for (int i=1,i<=7,i++){
float variable+i = ( (qIter = request.getQuery().find(variable+i))
== request.getQuery().end()
)
? 0.0
: atof(qIter->second.c_str());
if ( !isLegalNumber(request.getQuery(),variable+i,variable+i) )
{
strcpy(filePath,"yourErrorFilename.html");
}
else
{
// I want to add the x0 or xn variable here into a json
// The value is now in variable 'x'of something
}
}
Any insights appreciated.
edit: here's my isLegalNumber() method
bool isLegalNumber (const std::map<std::string,std::string>&
map,
const std::string& varName,
float& value
)
{
float temp;
char* cPtr;
std::map<std::string,std::string>::const_iterator
iter = map.find(varName);
if (iter == map.end())
return(false);
temp = strtod(iter->second.c_str(),&cPtr);
if ( (*cPtr != '\0') || (cPtr == iter->second.c_str()) )
return(false);
value = temp;
return(true);
}
im trying to convert a string/ dictionary into a json,
the first question would be how to add it into a dictionary,
and second, how to convert that dictionary into JSON.
basically i want the json to look like
{
x1: value of x1,
x2: value of x2,
....
x7: value of x7
}
I'm not totally clear what you're trying to do in your example code. Specifically, I don't know what the string value variable is used for. I'm guessing you actually want to define an array of floats. You can also skip the first step where you're setting the value to either 0.0 or atof(...) since your isLegalNumber function sets it later anyway. e.g.
float x[8] = {0.0f};
// Note that arrays in C++ are zero-indexed, so your iteration variable should start at 0
for (int i=0; i<=7; i++) {
std::string varName = "x";
varName.push_back(std::to_string(i+1)); // Append the index
if ( !isLegalNumber(request.getQuery(), varName, x[i] ) {
// Error
} else {
// Add to JSON structure
}
}
Once you've got that sorted out, for working with JSON in C++, I would strongly recommend using an existing open-source library such as JSON for Modern C++, rather than rolling your own implementation. This will make it much easier to build the JSON structure you need and ensure that it is properly formatted.
That library has quite thorough documentation, and it allows you to define JSON structures using very similar syntax to the actual JSON you're trying to write, e.g.
json j2 = {
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
// ...
};
Or in your specific case, define json j; outside the loop, and then in your if case you can do:
j[varName] = x[i];
And then you can convert it to a string using std::string s = j.dump();.

switch case on char*

It is a piece of code that gives me error:
const char* name = pAttr->Name(); // attribute name
const char* value = pAttr->Value(); // attribute value
switch(name) // here is where error happens: must have integral or enum type
{
case 'SRAD': // distance from focal point to iso center
double D = atof(value);
break;
case 'DRAD': // distance from iso center to detector
break;
default:
break;
}
The switch(name) is where error happens. It says it must be a integral or enum type. So how do I do switch case, or equivalent, on a char* type?
You cannot use switch here; as the error says, const char* is not supported. It's a good thing, too, because comparing two C-strings through pointers only compares the pointers, not the strings they point to (consider "hello" == "world").
Even if it were, you're trying to compare your C-string to multicharacter literals, which is certainly not what you intended, not least of all because they have type int and an implementation-defined value; I guess you meant to write "SRAD", not 'SRAD'.
Since you're using C++, you should do this:
const std::string name = pAttr->Name();
const std::string value = pAttr->Value();
if (name == "SRAD") {
double D = atof(value.c_str()); // use std::stod(value) in C++11
// ...
}
else if (name == "DRAD") {
// ...
}
else {
// ...
}
(I also fixed your use of name in the initialisation of D; Remy's right — you must have meant value here since "SRAD" cannot possibly be interpreted as a double.)
Another option is to use a local map to store integral values corresponding to the string values, get the integral value from the string, then, use switch on the integral value.
enum { SRAD = 1, DRAD, ... };
static std::map<std::string, int> localMap;
// Fill up the map.
if ( localMap.empty() )
{
localMap["SRAD"] = SRAD;
localMap["DRAD"] = DRAD;
}
const char* name = pAttr->Name(); // attribute name
const char* value = pAttr->Value(); // attribute value
int val = localMap[name];
switch (val)
{
case SRAD: // distance from focal point to iso center
{
double D = atof(value);
break;
}
case DRAD: // distance from iso center to detector
break;
default: // name is unknown
break;
}
Ok, this is totally, completely EVIL, but I have done it, and it does work:
// Must be a #define because an inline func won't give you a constant
#define MAKECODE(p) ((((p)[0])*0x01000000) \
+ (((p)[1])*0x00010000) \
+ (((p)[2])*0x00000100) \
+ ((p)[3]) )
// Note: I did not verify that the parenthesis matched.
switch(MAKECODE(name))
{
case MAKECODE("SRAD"): // distance from focal point to iso center
double D = atof(name);
break;
case MAKECODE("DRAD"): // distance from iso center to detector
break;
default:
break;
}
NOTE: BAD things will happen if the string name points to is less than 4 characters. Different bad things will happen is the string in the case statements are less than 4 characters (but probably just a compiler error).
this answer posted mostly for fun, but it will work if your name string is guaranteed to always be 4 bytes long.
#include <iostream>
using namespace std;
// precondition: name is exactly 4 chars in length
uint32_t convert(const char* name)
{
uint32_t val = uint32_t(name[3])
+ (uint32_t(name[2]) << 8)
+ (uint32_t(name[1]) << 16)
+ (uint32_t(name[0]) << 24);
return val;
}
int main()
{
const char* name = "SRAD"; // attribute name
const char* value = "10"; // attribute value
switch(convert(name)) // convert the string value to integral type uint32_t
{
case 'SRAD': // use arcane knowledge of C to construct an int32 representation of ascii digits
{
double D = atof(value);
cout << "SRAD " << D << endl;
break;
}
case 'DRAD': // distance from iso center to detector
cout << "some operation on value here " << endl;
break;
default:
break;
}
return 0;
}
A switch statement can only evaluate an expression of an integral or enumeration type (or convertible to such a type), and the expression in each case label must be a constant expression.
'SRAD' is not a string literal. It's a character literal with an implementation-defined value of type int. (This is a nearly useless language feature that I've seen used by mistake more than I've seen it used correctly.)
If you want to use C-style language features, avoiding things like C++'s std::string, the equivalent would be an if/else chain:
if (strcmp(name, "SRAD") == 0) {
// ...
}
else if (strcmp(name, "DRAD") == 0) {
// ...
}
else {
// ...
}
If you use std::string (which is advisable), the code would be similar, except that you can use == rather than strcmp.
You could set up a data structure that lets compute a discrete value that you can then use in a switch/case statement, as R Sahu's answer suggests. This would save the overhead of potentially doing N string comparisons. In my opinion, that would be overkill for a simple case like this. If your actual code is larger and more complex, it's worth considering.
Or you might consider redesigning your data structure so that you store and test an enumeration value directly, and then get a string value from that enumeration value via a lookup table.

Key Value Pair implementation C

I have a .txt file that stores student names along with two of their best marks. If a student for some reason, i.e. dropping out of course, fails to pass a course, then no marks are recorded.
My file looks like this
Samuel= 90.5, 95.9
Bill= 25.2, 45.3
Tim
Anthony= 99.9, 12.5
Mark
Rob
Basically, Tim, Mark and Rob failed the course and hence their marks are not stored. Also to differentiate between a failed mark and a pass mark, I have used the = symbol. Basically, I want to store all the names into memory alongside their associated values.
This is my implementation, however it is flawed in the sense that I have declared a double *marks[2] array to store all six marks, when clearly it will only store 3. I am having trouble storing the values into the double array.
This is my code...
istream& operator>> (istream& is, Students& student)
{
student.names = new char*[6];
for (int i=0; i<10; i++)
{
student.names[i] = new char[256];
student.marks[i] = new double[2];
is.getline(student.names[i], sizeof(student.names));
for (int j=0; j < 256; j++)
{
if((student.names[i][j] == '='))
{
int newPos = j + 1;
for (int k = newPos; k < 256; k++)
{
student.names[i][k - newPos] = student.names[k];
}
}
}
}
}
How can I go about storing the values of the students with the valid marks? Please, no use of vectors or stringstreams, just pure C/C++ char arrays
You have a few options, you could use a struct like so
struct Record {
std::string name;
double marks[2];
};
And then stick that into something like std::vector<Record> or an array of them like
Records *r = new Records[1000];
You could also keep three different arrays (either automatically allocated or dynamically allocated or even std::vector), one to hold the name, two to hold the marks.
In each case you would just indicate a fail by some thing like the marks being zero.
Also, you can use
std::string name;
double first, second;
std::cin >> name;
if (name[name.size() - 1] == '=')
std::cin >> first >> second;
And this will parse the input like you want it to for a single line. Once you've done that you can wrap the whole thing in a loop while sticking the values you get into some sort of data structure that I already described.
Hope that gives you a few ideas on where to go!
Here's a strategy:
First of all you need to implement a struct to hold the key-value pair, I suggest the following:
struct Student {
char name[30];
double marks[2];
};
Note that you can give the dimension of the char array inside the struct if you know that the length will never be higher. (which is given here)
Now what you need is to know how many lines are in your ifstream, you could make a loop of is.getline() calls to get there. (don't forget to call is.clear() and is.seekg(0) when finished, to be at the beginning for the real loop)
When you know how many lines are in your ifstream you can use dynamically cast the Array of your struct with the actual length of your file:
Student * students = new Student[lineCount]; // line count of is
As you can see, there's no need to have a std::vector to hold the values. Consider that the getline() loop may be an overkill just to get the line count, alternatively you could give a length to Students at compile-time by making an array with a length that will never be overpassed.
(e.g. Student students[128];)
Now you need to parse the lines, i'd suggest you make a loop like the following (line by line):
// int parseLine ( char* line, char* name, double* marks ) { ...
bool hasMarks=false;
int iLine=0; // Line pos iterator
int iName=0; // Name pos iterator
char mk1Str[4]; // String buffer, Mark 1
char mk2Str[4]; // String buffer, Mark 2
while(line[iLine]!='\0')
{
if(line[iLine]=='=')
{
hasMarks=true;
name[iLine]='\0';
for(int iMark=0;iMark<4;iMark++)
{
mk1Str[iMark]=line[iLine+iMark+2];
mk2Str[iMark]=line[iLine+iMark+8];
// ^^ You can harcode the offsets (2,8) since they don't change
}
break;
}
name[iName++]=line[iLine];
iLine++;
}
Now what you need is to parse the marks to double values, for this you could use the atof() function that works with char*. The bool hasMarks helps you know if a student has defined marks, if not, you could define dummy values like -1 for the mark fields of your struct.
I think this works quite well for your case...

How to get next value of enum

I have the following problem:
enum Language { English, French, German, Italian, Spanish };
int main() {
Language tongue = German;
tongue = static_cast<Language>(tongue + 1);
cout << tongue;
}
//it returns 3.....but i want to get the language name on index 3.....
I find that an explicit look up table works best, for both converting from enum to text and text to enum:
enum Language_Enum
{
LANGUAGE_FIRST = 0,
LANGUAGE_GERMAN = LANGUAGE_FIRST,
LANGUAGE_ENGLISH,
LANGUAGE_HOPI,
LANGUAGE_WELSH,
LANGUAGE_TEXAN,
LANGUAGE_DUTCH,
LANGUAGE_LAST
};
struct Language_Entry
{
Language_Enum id;
const char * text;
};
const Language Entry language_table[] =
{
{LANGUAGE_GERMAN, "German"},
{LANGUAGE_HOPI, "Hopi"},
{LANGUAGE_DUTCH, "Dutch"},
// ...
};
const unsigned int language_table_size =
sizeof(language_table) / sizeof(language_table[0]);
Specifying the enum along with the text, allows for the enum order to change with minimal effect to the search engine.
The LANGUAGE_FIRST and LANGUAGE_LAST identifiers allow for iteration of the enum:
Language_Enum l;
for (l = LANGUAGE_FIRST; l < LANGUAGE_LAST; ++l)
{
// ...
}
You'll have to create an array of strings which matches your enum e.g.
std::string[] LangTxt = { "English", "French", "German", "Italian", "Spanish" };
then you can reference them as follows:
cout << LangTxt[tongue];
Be careful to keep the definitions together though so they are updated side by side.
It is not so simple to print the enum name for a given enum value in C++. Instead, you can use a map or string array to hold the values, which do allow you to get both the index and the string value.
Best Way to use enum is first give initial value to your enum.
enum TestEnum
{
Zero=0,
One,
Two
}
Even you wont specify anything the default starting index is zero.
To get the value at a particular index simple do that
TestEnum(index);