I'm trying to figure out how to can fold a word from a string. For example "code" after the folding would become "ceod". Basically start from the first character and then get the last one, then the second character. I know the first step is to start from a loop, but I have no idea how to get the last character after that. Any help would be great. Heres my code.
#include <iostream>
using namespace std;
int main () {
string fold;
cout << "Enter a word: ";
cin >> fold;
string temp;
string backwards;
string wrap;
for (unsigned int i = 0; i < fold.length(); i++){
temp = temp + fold[i];
}
backwards= string(temp.rbegin(),temp.rend());
for(unsigned int i = 0; i < temp.length(); i++) {
wrap = fold.replace(backwards[i]);
}
cout << wrap;
}
Thanks
#Supreme, there are number of ways to do your task and I'm going to post one of them. But as #John had pointed you must try your own to get it done because real programming is all about practicing a lot. Use this solution just as a reference of one possibility and find many others.
int main()
{
string in;
cout <<"enter: "; cin >> in;
string fold;
for (int i=0, j=in.length()-1; i<in.length()/2; i++, j--)
{
fold += in[i];
fold += in[j];
}
if( in.length()%2 != 0) // if string lenght is odd, pick the middle
fold += in[in.length()/2];
cout << endl << fold ;
return 0;
}
good luck !
There are two approaches to this form of problem, a mathematically exact method would be to create a generator function which returns the number in the correct order.
An easier plan would be to modify the string to solve practically the problem.
Mathematical solution
We want a function which returns the index in the string to add. We have 2 sequences - increasing and decreasing and they are interleaved.
sequence 1 :
0, 1 , 2, 3.
sequence 2
len-1, len-2, len-3, len-4.
Given they are interleaved, we want even values to be from sequence 1 and odd values from sequence 2.
So our solution would be to for a given new index, choose which sequence to use, and then return the next value from that sequence.
int generator( int idx, int len )
{
ASSERT( idx < len );
if( idx %2 == 0 ) { // even - first sequence
return idx/2;
} else {
return (len- (1 + idx/2);
}
}
This can then be called from a function fold...
std::string fold(const char * src)
{
std::string result;
std::string source(src);
for (size_t i = 0; i < source.length(); i++) {
result += source.at(generator(i, source.length()));
}
return result;
}
Pratical solution
Although less efficient, this can be easier to think about. We are taking either the first or the last character of a string. This we will do using string manipulation to get the right result.
std::string fold2(const char * src)
{
std::string source = src;
enum whereToTake { fromStart, fromEnd };
std::string result;
enum whereToTake next = fromStart;
while (source.length() > 0) {
if (next == fromStart) {
result += source.at(0);
source = source.substr(1);
next = fromEnd;
}
else {
result += source.at(source.length() - 1); // last char
source = source.substr(0, source.length() - 1); // eat last char
next = fromStart;
}
}
return result;
}
You can take advantage of the concept of reverse iterators to write a generic algorithm based on the solution presented in Usman Riaz answer.
Compose your string picking chars from both the ends of the original string. When you reach the center, add the char in the middle if the number of chars is odd.
Here is a possible implementation:
#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>
#include <iterator>
template <class ForwardIt, class OutputIt>
OutputIt fold(ForwardIt source, ForwardIt end, OutputIt output)
{
auto reverse_source = std::reverse_iterator<ForwardIt>(end);
auto reverse_source_end = std::reverse_iterator<ForwardIt>(source);
auto source_end = std::next(source, std::distance(source, end) / 2);
while ( source != source_end )
{
*output++ = *source++;
*output++ = *reverse_source++;
}
if ( source != reverse_source.base() )
{
*output++ = *source;
}
return output;
}
int main() {
std::vector<std::pair<std::string, std::string>> tests {
{"", ""}, {"a", "a"}, {"stack", "sktca"}, {"steack", "sktcea"}
};
for ( auto const &test : tests )
{
std::string result;
fold(
std::begin(test.first), std::end(test.first),
std::back_inserter(result)
);
std::cout << (result == test.second ? " OK " : "FAILED: ")
<< '\"' << test.first << "\" --> \"" << result << "\"\n";
}
}
In my game I keep track of unlocked levels with a vector std::vector<bool> lvlUnlocked_;.
The simple function to save the progress is this:
void save() {
std::stringstream ss;
std::string stringToSave = "";
std::ofstream ofile("./progress.txt");
if (ofile.good()) {
ofile.clear();
for (std::size_t i = 0; i < levelUnlocked_.size(); ++i) {
ss << "lvl" << i << "=" << (lvlUnlocked_.at(i) ? "1" : "0") << std::endl;
}
stringToSave = ss.str();
ofile << stringToSave;
ofile.close();
}
}
This works and is nice since I can just use a loop to dump the info.
Now to the part where I am stuck, the lower part of my load function (see comment in code below):
void load() {
std::ifstream ifile("./progress.txt");
if (ifile.good()) {
int begin;
int end;
std::string line;
std::string stringKey = "";
std::string stringValue = "";
unsigned int result;
while (std::getline(ifile, line)) {
stringKey = "";
stringValue = "";
for (unsigned int i = 0; i < line.length(); i++) {
if (line.at(i) == '=') {
begin = i + 1;
end = line.length();
break;
}
}
for (int i = 0; i < begin - 1; i++) {
stringKey += line.at(i);
}
for (int i = begin; i < end; i++) {
stringValue += line.at(i);
}
result = static_cast<unsigned int>(std::stoi(stringValue));
// usually I now compare the value and act accordingly, like so:
if (std::strcmp(stringKey.c_str(), "lvl0") == 0) {
lvlUnlocked_.at(0) = true;
} else if (std::strcmp(stringKey.c_str(), "lvl1") == 0) {
lvlUnlocked_.at(1) = true;
} else if (std::strcmp(stringKey.c_str(), "lvl2") == 0) {
lvlUnlocked_.at(2) = true;
}
// etc....
}
}
}
This works fine, but...
the problem is that I have 100+ levels and I want it to be dynamic based on the size of my lvlUnlocked_ vector instead of having to type it all like in the code above.
Is there a way to somehow make use of a loop like in my save function to check all levels?
If you parse your key to extract a suitable integer value, you can just index into the bit-vector with that:
while (std::getline(ifile, line)) {
const size_t eq = line.find('=');
if (eq == std::string::npos)
// no equals sign
continue;
auto stringKey = line.substr(0, eq);
auto stringValue = line.substr(eq+1);
if (stringKey.substr(0,3) != "lvl")
// doesn't begin with lvl
continue;
// strip off "lvl"
stringKey = stringKey.substr(3);
size_t end;
std::vector<bool>::size_type index = std::stoi(stringKey, &end);
if (end == 0 || end != stringKey.length())
// not a valid level number
continue;
if (index >= lvlUnlocked_.size())
// out of range
continue;
// Set it :-)
lvlUnlocked_[index] = stringValue=="1";
}
(I've also updated your parsing for "key=value" strings to more idiomatic C++.)
class ORF_Finder {
public:
void findORFs(string & strand, int sizeOfStrand);
vector<string> orf1Strands;
vector<string> orf2Strands;
vector<string> orf3Strands;
private:
string newStrand;
string newSub;
};
void ORF_Finder::findORFs(string & strand, int sizeOfStrand) {
int pos, pos1, index = 0;
for (int i = 0; i < strand.size(); i++) {
pos = strand.find("ATG");
pos1 = strand.find("TAA");
newSub = strand.substr(pos, pos1);
newStrand.insert(index, newSub);
strand.erase(pos, pos1);
index = index + 3;
if ((pos1 % 3 == 0) && (pos1 >= pos + 21)) {
orf1Strands.push_back(newStrand);
}
else if ((pos1 % 3 == 1) && (pos1 >= pos + 21)) {
orf2Strands.push_back(newStrand);
}
else if ((pos1 % 3 == 2) && (pos1 >= pos + 21)) {
orf3Strands.push_back(newStrand);
}
}
}
^ assume all strings are declared and I'm "using namespace std".
My goal is to ask the user for an imported DNA strand (ex: "TCAATGCGCGCTACCATGCGGAGCTCTGGGCCCAAATTTCATCCATAACTGGGGCCCTTTTAAGGGCCCGGGAAATTT") and find all instances where a substring starts with "ATG" and ends with "TAA", "TAG", or "TGA" (I omitted "TAG" and "TGA" for simplicity sake).
The substring will be as so: "ATG ... ... ... ... TAA" and then it will be stored into a vector to be utilized later. However, I would like to find multiple instances of each reading frame (ORF1 should start at the "T" of the imported strand, ORF2 should start at the "C" of the imported strand, and ORF3 should start at the "A" of the imported strand) and should work in triplets, hence the inclusion of mod 3 in the if statements. The purpose of "pos1 >= pos + 21" is so that every substring is at least seven codons long.
The above code is what I've done thus far but obviously, it's incorrect. I'm trying to tell pos to find "ATG" and pos1 to find "TAA". newSub is the substring that will be generated from "ATG" to "TAA" and newStrand will be generated to contain the substring. I would then erase the portion of the strand (to avoid repetition) and increment index.
Sorry for the long description but I've been stressing over this and I've tried everything in my willpower to solve this.
Knutt-Morris Pratt is the fastest solution. Aho-corasick algorithm its a generalized version from kmp algorithm. Basically its a trie with failure links computed from a breadth-first search. You can try my PHP implementation phpahocorasick # codeplex.com. Then you need to add a wildcard to find all substrings.
Here is a possible implementation.
Characteristics :
can process large strings since it only keep one single copy of the initial string
accept one arbitrary initial sequence (here "ATG")
accept many end sequences (here "TAA", "TAG", or "TGA")
accept only substring of at least 7 codons
substrings are only described by there index in initial string and length (to save memory)
per your requirement keep results in 3 different vectors according to the modulo 3 of their index
Code :
#include <iostream>
#include <string>
#include <stdexcept>
#include <vector>
class Strand {
const std::string* data;
size_t begin;
size_t len;
public:
Strand(const std::string& data, size_t begin, size_t end): begin(begin),
len(end - begin), data(&data) {
if (end <= begin) {
throw std::invalid_argument("end < begin");
}
}
std::string getString() const {
const char *beg = data->c_str();
beg += begin;
return std::string(beg, len);
}
};
class Parser {
const std::string& data;
const std::string& first;
const std::vector<std::string>& end;
size_t dataLen;
std::vector<Strand> orf1Strands;
std::vector<Strand> orf2Strands;
std::vector<Strand> orf3Strands;
public:
enum TypStrand {
one = 0, two, three
};
Parser(const std::string& data, const std::string& first,
const std::vector<std::string>& end): data(data),
first(first), end(end) {
dataLen = data.length();
}
void parse();
const std::vector<Strand>& getVector(int typ) const {
switch(typ) {
case 0 : return orf1Strands;
case 1 : return orf2Strands;
default : return orf3Strands;
}
}
const std::vector<Strand>& getVector(TypStrand typ) const {
return getVector((int) typ);
}
};
void Parser::parse() {
size_t pos=0;
size_t endSize = end.size();
std::string firstChars = "";
for(size_t i=0; i<endSize; i++) {
firstChars += end[i].at(0);
}
for(;;) {
pos = data.find(first, pos);
if (pos == std::string::npos) break;
size_t strandEnd = pos + 18;
for(;;) {
if (strandEnd + 3 >= dataLen) break;
strandEnd = data.find_first_of(firstChars, strandEnd);
if ((strandEnd - pos) % 3 != 0) {
strandEnd += 1;
continue;
}
if (strandEnd + 3 >= dataLen) break;
for (size_t i=0; i<endSize; i++) {
if (data.compare(strandEnd, end[i].length(), end[i]) == 0) {
std::cout << "Found sequence ended with " << end[i] << std::endl;
switch(pos %3) {
case 0 :
orf1Strands.push_back(Strand(data, pos,
strandEnd + 3));
break;
case 1 :
orf2Strands.push_back(Strand(data, pos,
strandEnd + 3));
break;
case 2 :
orf3Strands.push_back(Strand(data, pos,
strandEnd + 3));
break;
}
pos = strandEnd + end[i].length() - 1;
break;
}
}
if (pos > strandEnd) break;
strandEnd += 3;
}
if (strandEnd + 3 >= dataLen) break;
pos = pos + 1;
}
}
using namespace std;
int main() {
std::string first = "ATG";
vector<string> end;
std::string ends[] = { "TAA", "TAG", "TGA"};
for (int i=0; i< sizeof(ends)/sizeof(std::string); i++) {
end.push_back(ends[i]);
}
string data = "TCAATGCGCGCTACCATGCGGAGCTCTGGGCCCAAATTTC"
"ATCCATAACTGGGGCCCTTTTAAGGGCCCGGGAAATTT";
Parser parser(data, first, end);
parser.parse();
for (int i=0; i<3; i++) {
int typ = i;
const vector<Strand>& vect = parser.getVector(typ);
cout << "Order " << i << " : " << vect.size() << endl;
if (vect.size() > 0) {
for(size_t j=0; j<vect.size(); j++) {
cout << vect[i].getString() << endl;
}
}
}
return 0;
}
Todo :
add comments
fix the management of enum TypStrand : once the program is written, I think that it would be better to have an array of three vectors than three separate ones.
minimal number of codons should be configurable
test more intensively for corner cases
3 is a magic number and really should be expressed as a constant
Simple:
Scan the whole string for occurrances of the start or end sequences.
If you find an end sequence, extract the part from the previous start sequence.
You will have a few cornercases like e.g. the handling of multiple signal sequences that could be paired differently, but that's all just normal programming.
The problem with your approach is that you don't scan the string from start to end, but you repeatedly search for the start and end from the beginning. You need to continue after the last position instead. Check out the various find.. functions of the string class to get an idea how to do that.
I am working on a algorithm where I am trying the following output:
Given values/Inputs:
char *Var = "1-5,10,12,15-16,25-35,67,69,99-105";
int size = 29;
Here "1-5" depicts a range value, i.e. it will be understood as "1,2,3,4,5" while the values with just "," are individual values.
I was writing an algorithm where end output should be such that it will give complete range of output as:
int list[]=1,2,3,4,5,10,12,15,16,25,26,27,28,29,30,31,32,33,34,35,67,69,99,100,101,102,103,104,105;
If anyone is familiar with this issue then the help would be really appreciated.
Thanks in advance!
My initial code approach was as:
if(NULL != strchr((char *)grp_range, '-'))
{
int_u8 delims[] = "-";
result = (int_u8 *)strtok((char *)grp_range, (char *)delims);
if(NULL != result)
{
start_index = strtol((char*)result, (char **)&end_ptr, 10);
result = (int_u8 *)strtok(NULL, (char *)delims);
}
while(NULL != result)
{
end_index = strtol((char*)result, (char**)&end_ptr, 10);
result = (int_u8 *)strtok(NULL, (char *)delims);
}
while(start_index <= end_index)
{
grp_list[i++] = start_index;
start_index++;
}
}
else if(NULL != strchr((char *)grp_range, ','))
{
int_u8 delims[] = ",";
result = (unison_u8 *)strtok((char *)grp_range, (char *)delims);
while(result != NULL)
{
grp_list[i++] = strtol((char*)result, (char**)&end_ptr, 10);
result = (int_u8 *)strtok(NULL, (char *)delims);
}
}
But it only works if I have either "0-5" or "0,10,15". I am looking forward to make it more versatile.
Here is a C++ solution for you to study.
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int ConvertString2Int(const string& str)
{
stringstream ss(str);
int x;
if (! (ss >> x))
{
cerr << "Error converting " << str << " to integer" << endl;
abort();
}
return x;
}
vector<string> SplitStringToArray(const string& str, char splitter)
{
vector<string> tokens;
stringstream ss(str);
string temp;
while (getline(ss, temp, splitter)) // split into new "lines" based on character
{
tokens.push_back(temp);
}
return tokens;
}
vector<int> ParseData(const string& data)
{
vector<string> tokens = SplitStringToArray(data, ',');
vector<int> result;
for (vector<string>::const_iterator it = tokens.begin(), end_it = tokens.end(); it != end_it; ++it)
{
const string& token = *it;
vector<string> range = SplitStringToArray(token, '-');
if (range.size() == 1)
{
result.push_back(ConvertString2Int(range[0]));
}
else if (range.size() == 2)
{
int start = ConvertString2Int(range[0]);
int stop = ConvertString2Int(range[1]);
for (int i = start; i <= stop; i++)
{
result.push_back(i);
}
}
else
{
cerr << "Error parsing token " << token << endl;
abort();
}
}
return result;
}
int main()
{
vector<int> result = ParseData("1-5,10,12,15-16,25-35,67,69,99-105");
for (vector<int>::const_iterator it = result.begin(), end_it = result.end(); it != end_it; ++it)
{
cout << *it << " ";
}
cout << endl;
}
Live example
http://ideone.com/2W99Tt
This is my boost approach :
This won't give you array of ints, instead a vector of ints
Algorithm used: (nothing new)
Split string using ,
Split the individual string using -
Make a range low and high
Push it into vector with help of this range
Code:-
#include<iostream>
#include<vector>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
int main(){
std::string line("1-5,10,12,15-16,25-35,67,69,99-105");
std::vector<std::string> strs,r;
std::vector<int> v;
int low,high,i;
boost::split(strs,line,boost::is_any_of(","));
for (auto it:strs)
{
boost::split(r,it,boost::is_any_of("-"));
auto x = r.begin();
low = high =boost::lexical_cast<int>(r[0]);
x++;
if(x!=r.end())
high = boost::lexical_cast<int>(r[1]);
for(i=low;i<=high;++i)
v.push_back(i);
}
for(auto x:v)
std::cout<<x<<" ";
return 0;
}
You're issue seems to be misunderstanding how strtok works. Have a look at this.
#include <string.h>
#include <stdio.h>
int main()
{
int i, j;
char delims[] = " ,";
char str[] = "1-5,6,7";
char *tok;
char tmp[256];
int rstart, rend;
tok = strtok(str, delims);
while(tok != NULL) {
for(i = 0; i < strlen(tok); ++i) {
//// range
if(i != 0 && tok[i] == '-') {
strncpy(tmp, tok, i);
rstart = atoi(tmp);
strcpy(tmp, tok + i + 1);
rend = atoi(tmp);
for(j = rstart; j <= rend; ++j)
printf("%d\n", j);
i = strlen(tok) + 1;
}
else if(strchr(tok, '-') == NULL)
printf("%s\n", tok);
}
tok = strtok(NULL, delims);
}
return 0;
}
Don't search. Just go through the text one character at a time. As long as you're seeing digits, accumulate them into a value. If the digits are followed by a - then you're looking at a range, and need to parse the next set of digits to get the upper bound of the range and put all the values into your list. If the value is not followed by a - then you've got a single value; put it into your list.
Stop and think about it: what you actually have is a comma
separated list of ranges, where a range can be either a single
number, or a pair of numbers separated by a '-'. So you
probably want to loop over the ranges, using recursive descent
for the parsing. (This sort of thing is best handled by an
istream, so that's what I'll use.)
std::vector<int> results;
std::istringstream parser( std::string( var ) );
processRange( results, parser );
while ( isSeparator( parser, ',' ) ) {
processRange( results, parser );
}
with:
bool
isSeparator( std::istream& source, char separ )
{
char next;
source >> next;
if ( source && next != separ ) {
source.putback( next );
}
return source && next == separ;
}
and
void
processRange( std::vector<int>& results, std::istream& source )
{
int first = 0;
source >> first;
int last = first;
if ( isSeparator( source, '-' ) ) {
source >> last;
}
if ( last < first ) {
source.setstate( std::ios_base::failbit );
}
if ( source ) {
while ( first != last ) {
results.push_back( first );
++ first;
}
results.push_back( first );
}
}
The isSeparator function will, in fact, probably be useful in
other projects in the future, and should be kept in your
toolbox.
First divide whole string into numbers and ranges (using strtok() with "," delimiter), save strings in array, then, search through array looking for "-", if it present than use sscanf() with "%d-%d" format, else use sscanf with single "%d" format.
Function usage is easily googling.
One approach:
You need a parser that identifies 3 kinds of tokens: ',', '-', and numbers. That raises the level of abstraction so that you are operating at a level above characters.
Then you can parse your token stream to create a list of ranges and constants.
Then you can parse that list to convert the ranges into constants.
Some code that does part of the job:
#include <stdio.h>
// Prints a comma after the last digit. You will need to fix that up.
void print(int a, int b) {
for (int i = a; i <= b; ++i) {
printf("%d, ", i);
}
}
int main() {
enum { DASH, COMMA, NUMBER };
struct token {
int type;
int value;
};
// Sample input stream. Notice the sentinel comma at the end.
// 1-5,10,
struct token tokStream[] = {
{ NUMBER, 1 },
{ DASH, 0 },
{ NUMBER, 5 },
{ COMMA, 0 },
{ NUMBER, 10 },
{ COMMA, 0 } };
// This parser assumes well formed input. You have to add all the error
// checking yourself.
size_t i = 0;
while (i < sizeof(tokStream)/sizeof(struct token)) {
if (tokStream[i+1].type == COMMA) {
print(tokStream[i].value, tokStream[i].value);
i += 2; // skip to next number
}
else { // DASH
print(tokStream[i].value, tokStream[i+2].value);
i += 4; // skip to next number
}
}
return 0;
}
I found a bug on the function below. When temp = 10. It will convert temp to string '01'. instead of string'10'. I can't tell why?
Is there any better to convert Num to Str? Thanks.
completed Num2Str() as this,
static bool Num2Str(string& s, const T& value)
{
int temp = static_cast<int>(value); // When temp = 10.
s.push_back(char('0' + temp % 10));
temp /= 10;
while(temp != 0)
{
s.push_back(char('0' + temp % 10));
temp /= 10;
}
if(s.size() == 0)
{
return false;
}
if(s.find_first_not_of("0123456789") != string::npos)
{
return false;
}
return true;
}
Use std::ostringstream to convert numbers to strings.
Don't use free static functions in C++; use unnamed namespaces instead.
#include<sstream>
#include<string>
namespace {
void f()
{
int value = 42;
std::ostringstream ss;
if( ss << value ) {
std::string s = ss.str();
} else {
// failure
}
}
}
For a solution in the flavour of the existing code (although I'd prefer the existing built int to string conversion):
template<class T>
static std::string Num2Str(const T& value)
{
std::string s;
int temp = static_cast<int>(value);
if (!temp)
{
s = "0";
return s;
}
while(temp != 0)
{
s.insert(0,1,(char('0' + temp % 10)));
temp /= 10;
}
return s;
}
Need to add support for negative values, range checking, etc.
My favorite is the recursive version (mostly in C) for flipping the digits to be in the correct order.
void u2str(string& s, unsigned value){
unsigned d = value % 10;
value /= 10;
if (value > 0 )
u2str(s,value);
s.push_back('0'+d);
}
For 0, you get "0", but in all other cases you don't get leading zeros. As shown it assumes string is more efficient at appending than inserting. However, if inserting is, then you don't need the recursive trick (eg Keith's answer).
You could also use boost::lexical_cast (see http://www.boost.org/doc/libs/1_46_1/libs/conversion/lexical_cast.htm)
For example:
void log_message(const std::string &);
void log_errno(int yoko)
{
log_message("Error " + boost::lexical_cast<std::string>(yoko) + ": " + strerror(yoko));
}