I'm attempting to write alil function here which basically reads from a string. It reads every three characters and evaluates it using the pre-condition (if statement). If conditions are met, it would replace those three letters with new three letters. Then it would output the new string.
I tried writing the code but cant seem to get the logic right. the program runs but it doesn't print out anything. Dont mind the function name and the inaccuracy. I'm just doing a sample function to test this out.
string amino_acids(string line)
{
string acid;
string acids;
string newline;
for( int i= 0; i < line.length(); i++)
{
acid = line[i];
}
for (int i = 0; i < 3; i++)
{
acids = acid[i];
if(acids == "GUU")
{
acids = "ZAP";
}
newline = acids;
}
cout << "Acids: " <<newline <<endl;
return newline;
}
for( int i= 0; i < line.length(); i++)
acid = line[i];
Say line contains "abcd", this loop is going to do:
acid = 'a';
acid = 'b';
acid = 'c';
acid = 'd';
Only the last assignment has any lasting affect. If you need to actually get three characters from line into acid - you probably want to use += to add characters into acid, rather than =. But, if you loop over all of line like this, you'll end up doing acid = line;. I assume you want something more like acid = line.substr(0, 3)?
for (int i = 0; i < 3; i++)
{
acids = acid[i];
This is going to crash. acid is definitely a single character string, and you're indexing into acid[1] and acid[2] on the 2nd and 3rd iterations. While you're learning C++, you should probably use .at(i) which will throw an exception when you attempt to use an invalid index - you can catch the exception and at least have some indication of the problem. As is, it's undefined behaviour.
To use at, you need a try / catch block... the basic form is:
int main()
try
{
...your code in here...
some_string.at(i);
}
catch (const std::exception& e)
{
std::cerr << "caught exception: " << e.what() << '\n';
}
More generally, try putting some std::cout statements throughout your code so you know what values your variables actually have... you would easily have seen that they weren't what you expected. Alternatively, use an interactive debugger and watch the affect of each statement's execution.
Indexing a std::string with the [] operator yields a char, for which there just happens to be an overloaded operator= for strings.
Even if you were looping as I believe you intended (which, as the comments on the question mention, you probably aren't) because acids (which takes the value of a single character) will never be equal to the three character string you're comparing it to. Thus, no replacements will be performed.
To do what you want, try something like this:
for (int i = 0; i + 3 < line.length(); i += 3) // counting by 3 until end of line
{
if (line.substr(i, 3) == "GUU") // if the substring matches
{
line.assign("ZAP", i, 3); // overwrite it with new substring
}
}
return line;
Reading from your description, you want something like so
//note below does not compile, its just psuedo-code
string amino_acid(const string& sequence){
string result = sequence; //make copy of original sequence
For i = 0 to sequence.length - 3
string next3Seq = sequence(i,3); //grab next 3 character from current index
If next3Seq == 'GUU' //if the next next three sequence is 'GUU'
then result.replace(i,3,'ZAP'); //replace 'GUU' with 'ZAP'
EndIf
EndFor
return result;
}
You can use that as a start to code. Good Luck.
According to my understanding of your question. I have written some code. Please look below
string acids;
string newLine;
int limit=1;
for(int i=0;i<line.length();i++)
{
acids=acids+line[i];
if(limit==3)//Every 3 characters
{
if(acids == "GUU")
{
acids = "ZAP";
}
limit=1;
acids=""
newline=newline+acids;
}
limit++;
return newline;
}
Related
I'm very new to c++, but I do have experience with other object oriented programming languages.
I'm attempting to alphabetically sort the lines in a file I have, which has roughly 5300 lines. I originally wrote the program in c++ for practice, but was curious to see how it would perform against my main language, c#.
To my surprise, the same sorting algorithm which takes my c++ function 18-20 seconds to execute, finishes in less than 3 seconds in c#.
Given that I am very new to c++ (and not a very experienced programmer in general), I am sure this must be an error in the way I wrote something.
With all that being said, I am aware that there are quicker sorting methods to use. However, both programs are using the same algorithm so I don't understand the reason for the large performance gap.
I will note that I have tried converting the data to an array instead of a vector, but sorting the array was only consistently about 3 seconds faster (about 15 seconds total instead of 18).
What am I doing wrong? Any/all help is appreciated!
Below is the c++:
void select_sort_alphabetical(std::vector<std::string> _vector)
{
std::cout << "<< SORTING... >>" << "\n\n";
int char_index, i, j, size = _vector.size(), loop_iterations = 0;
char char1, char2;
std::string temp;
// Iterate through all lines
for (i = 0; i < (size - 1); i++)
{
for (j = (1 + i); j < size; j++)
{
char_index = 0;
char1 = _vector[i][char_index]; // Getting first character of each line
char2 = _vector[j][char_index];
// While the letters to be compared are the same, move onto the next character
while (char1 == char2)
{
char_index++;
char1 = _vector[i][char_index]; // Setting chars to the next characters in each line
char2 = _vector[j][char_index];
}
// Once the characters are different - if line x.ascii_code greater than line x+1.ascii_code...
if (_vector[i][char_index] > _vector[j][char_index]) // comparing characters
{
// Swapping places
temp = _vector[i];
_vector[i] = _vector[j];
_vector[j] = temp;
}
loop_iterations++;
}
}
//print_lines_from_vect(_vector);
// Clearing contents of vector and freeing up memory (trying to, anyway)
_vector.clear();
_vector.shrink_to_fit();
std::cout << "\nIterations: " << loop_iterations << "\n";
}
and here is the c#:
public static string[] select_sort_alphabetical(string[] lines, ref int loop_iterations)
{
Console.WriteLine("<< SORTING... >>");
// Iterate through all lines
for (int i = 0; i < (lines.Length - 2); i++)
{
for (int j = (1 + i); j < (lines.Length); j++)
{
int char_index = 0;
char char1 = lines[i][char_index]; // Getting first character of each line
char char2 = lines[j][char_index];
// While the letters to be compared are the same, move onto the next character
while (char1 == char2)
{
char_index++;
char1 = lines[i][char_index];
char2 = lines[j][char_index];
}
// Once the characters are different - if line x.ascii_code greater than line x+1.ascii_code...
if (lines[i][char_index] > lines[j][char_index]) // comparing characters
{
// Swapping places
string temp = lines[i];
lines[i] = lines[j];
lines[j] = temp;
}
loop_iterations++;
}
}
return lines;
}
One reason your algorithm would be slower, without taking in account other differences between languages, is swapping lines:
// Swapping places
string temp = lines[i];
lines[i] = lines[j];
lines[j] = temp;
in c#, string temp = original means temp and original point to the same string. modifying each will reflect in the other.
in c++, string temp = original means temp is a new string. Modifying one will not modify the other.
C++ provides move class members, which allow new objects to "steal" the resources of the original object.
std:.swap, in order to swap objects, make something like
string temp = steal(lines[i]);
lines[i] = steal(lines[j]);
lines[j] = steal(temp);
This is a simplification of the real mechanism.
Btw, if you use swap, you will see far faster debug, because that line swapping is a big cost in your algorithm.
In the method below, I have a two-dimensional array of characters called myarr and a string called code. I go through each character in code using the counter i, and look for a character in myarr that matches code[i]. When I find the character in myarr that matches code[i], I want to exit both of the for loops and the if statement and go back to the beginning of the while loop. The only way I can think of doing this is by using a goto statement. However, using goto is generally discouraged, so I was wondering if there was any other way to achieve this.
string decrypt(string code, char myarr[][5])
{
int r = 0;
int c = 0;
int i = 0;
string newstr = "";
while(i<code.length()-1)
{
//This is where I want to go back to
if (code[i] != ' ')
{
for (r = 0; r < 4; r++)
{
for (c = 0; c < 4; c++)
{
if (code[i] = myarr[r][c])
{
newstr += myarr[c][r];
i++;
//This is where I want to exit
}
}
}
}
else
{
newstr += " ";
i++;
}
}
return newstr;
}
You use a flag-ish variabele.
set a boolean to true at the beginning of the while loop.
then when the condition is met, you set it to false.
in every inner loop you also check for that flag being true.
Also. in my opinion this is one of the cases where goto is justified.
What I'd do:
char decrypthelper(char codech, // returns the substitution character for codech
const char myarr[][5]) //const because we aren't changing myarr.
// This will make sure we don't, and maybe
// the compiler can do something sneaky.
{
if (codech != ' ')
{
for (int r = 0; r < 5; r++) // fixed off by one error
// declare index variable here. No one else needs it
{
for (int c = 0; c < 5; c++) // fixed off by one error
{
if (codech == myarr[r][c]) // was assignment not compare
{
return myarr[c][r]; // found substitution. Exit
}
}
}
}
else
{
return ' '; // space... the final frontier
}
return '?'; // unknown character
}
string decrypt(string code, char myarr[][5])
{
string newstr = "";
for (auto codech: code) // for each character in code
{
newstr += decrypthelper(codech, myarr); // add substitution character
}
return newstr;
}
I tried to keep the code recognizable. There are a whole bunch of other tricks you can use to make your job a lot easier, so once you have your program up and running and bug free, take Quentin's suggestion about asking for a code review.
Note that many returns in a function is viewed in some circles as just as bad as goto.
As others have mentioned you can use a flag-ish variable. You can also use an exception as a way to break out of multiple loops.
You can also put the two inner loops into a separate function and use return.
But looking at the code why not change the algorithm? You should create a map from char to decrypted char so you can simply use:
newstr += map[code[i]];
I have an input string which I will use to build an output string. The output string is much the same as the input string but has some slight changes along the way, depending on if we hit a certain characters in the input. The code looks like this
outputTree(std::ostream& o, const char* input) {
size_t len = strlen(input);
int indent = 0;
string output;
for(size_t i = 0; i < input_len; i++) {
if(input[i] == '(') {
indent++;
output.append(1,'\n');
for(int j = 0; j < indent; j++) {
output.append(" ");
}
}
if(input[i] == ')') {
output.append(1,'\n');
for(int j = 0; j < indent; j++) {
output.append(" ");
}
indent--;
}
output.append(1,input[i]);
}
o << output << endl;
}
While this works, doing it character by character is pretty slow. Can anyone recommend some better approaches to this (pref with standard features, ie no boost)?
I am not sure what "pretty slow" means and how much improvement you expect. The algorithm you have is an efficient O(N) algorithm. The only thing you can do is trying to optimise individual operations, but then again I am not sure what kind of optimisations is the compiler doing.
One thing you could do is get rid of the inner loops that write the indentation string as many times is needed by the level of indentation (your indent variable). So instead of writing a newline and then execute the for loop, you can perform just one append that has the newline concatenated with the right amount of indentation. If you can set a limit to the depth of your indentation (say 10 levels deep) you can then create an array that has all 10 different indentation strings (all strings starting with a newline).
Another thing you can try is to use std::string::find to find the occurrences of '(' and ')' and do string copies up to these markers, instead of copying character by character.
Finally, note that your code might not behave as you want it, if the input is not as expected. Notice what will happen if you first encounter a ')' without having a corresponding '('.
I am making a Sudoku program and my i have a test.txt file that reads
53__7____
6__195___
_98____6_
8___6___3
4__8_3__1
7___2___6
_6____28_
___419__5
____8__79
where the "_" are actually spaces. The reason i give you _ is so you can see that there are literally only 9 characters on each line.
I was thinking that I would have to do something like having GRID[row][column], however I frankly don't know what types I should put my arrays as and I am just lost.
I simply want to make it so when i want to output say GRID[0][0] it returns 5, while if i ask for GRID[0][3] it returns a ' '.
It is getting it so the array store both the numbers and the spaces is where i am getting completely lost
What I currently have tried so far:
int main()
{
ifstream myfile(test.txt);
string line;
char sudoku_grid[9][9];
if (myfile.is_open())
{
while(myfile.good())
{
getline(myfile, line);
cout << sudoku_grid[line] << endl;
}
myfile.close();
}
else cout << "error";
return 0;
}
it returns the error line 12: no match for 'operator [ ]' in 'sudoku_grid[line]'
Here is my attempt though guidelines through you guys:
int main()
{
ifstream myfile(test.txt);
string line;
char sudoku_grid[9][9];
if (myfile.good())
{
for(int i = 0; i < 9; i++)
{
getline(myfile, line);
for(int j = 0; j < 9; j++)
{
if (line[j] == ' ')
sudoku_grid[j][i] = -1;
else sudoku_grid[j][i] = line[i];
}
cout << sudoku_grid[i] << endl;
}
myfile.close();
}
else cout << "error";
return 0;
}
The result is a very awkward answer of strange letters and a new numbers.
I'll just give you the algorithm/logic, not going to write the code for you. Try it and come back when stuck.
Initialize output in memory 2D array: numbers[9][9]
Open the file
Until there is no line left in the file:
a. Get the line i
b. Until there are no more characters in the line:
b1. Get each character of the line c
b2. If the character is not space, then numbers[i]=c, else numbers[i]=-1
Your array can be made up of int and in b2 if a whitespace is encountered you can insert -1 to indicate the absence of a number. Of course your code manipulating numbers array needs to take that into account.
Since you need to store both chars and integer type values, use char. each of your integer lies in the range 0-9, so can be stored as a character.
char Grid[9][9];
now you can read each character from the string and store it in the array. It will not only keep your spaces intact but also each character. Always remember to use ASCII codes to access the elements of the grid. For 0-9, ASCII codes are 48-57, ASCII code for space is 32.
Hope it helps...
Edit code: Here is the simplest example... PLace your test file in d:, or edit the path of file in code
int main (void)
{
FILE *fp = fopen("d:\\test.txt","r");
char sudoku_grid[9][9], ch;
// I am assuming that file is valid and data in that is also valid
if(fp)
{
for(int i = 0; i < 9; i++)
{
for(int j = 0; j < 9; j++)
{
//too read each character
ch = fgetc(fp);
sudoku_grid[i][j] = ch;
}
// to read '\n' from the line
ch = fgetc(fp);
}
//for checking if data went correctly
for(int i = 0; i< 9;i++)
{
for(int j= 0; j<9;j++)
cout<<sudoku_grid[i][j];
cout<<endl;
}
}
return 0;
}
In the first code you get the error message because sudoku_grid can
only be indexed by numbers and not by strings.
In the second code the line
sudoku_grid[j][i] = line[i];
should probably be
sudoku_grid[j][i] = line[j];
Does this answer your question?
I am working on a program to decrypt text with a certain key. I'm trying to use replace() but it doesn't seem to be working. For example, qwert should decrypt to hello, but the output is hlllo; in this case the w in qwert gets decrypted to e but then re-decrypted to l.
input:
xnm ceuob lrtzv ita hegfd tsmr xnm ypwq ktj
should come out as:
the quick brown fox jumps over the lazy dog
I'm getting:
oga yaacd brozn aox gamav ovar oga lazy dog
How can I fix this?
int main()
{
// ...
myFile.open("decrypt.txt");
while (myFile.good())
{
getline(myFile, line2);
// now line2 is, e.g., "xnm ceuob lrtzv ita hegfd tsmr xnm ypwq ktj"
// help here
for (int i = 0; i < 26; i++)
{
replace(line2.begin(), line2.end(), key[i], fox[i]);
}
v.push_back(line2);
}
myFile.close();
for (int i = 0; i < numline; i++)
{
cout << "line " << i <<" = " << v[i] << endl;
}
return 0;
}
By making 26 separate substitutions, the later ones are stepping on the results of the earlier ones. You need to find a way to make each substitution occur only once per character.
You need to decrypt each character once. Instead of having two arrays, key and fox, which (apparently) contain characters to substitute, you might consider building a map between input characters and their decrypted versions. Then you can simply walk over the input string, decrypting a character at a time.
std::map<char, char> lookup;
// populate lookup such that lookup['q'] = 'h', lookup['w'] = 'e', etc.
// walk over line2, decrypting a character at a time.
for (int i = 0; i < line2.length(); i++)
{
char c = line2[i];
char d = lookup[c];
line2[i] = d;
// or, if you want to keep it on one line:
// line2[i] = lookup[line2[i]];
}
In C++ you can access and modify string elements with square brackets. For example:
String str("dog");
str[1] = 'c';
//str = "dcg"
So you can use this notation instead of replace(). If replacing doesn't work as you intend it to then maybe your key is wrong.