String to double conversion without sstream or boost lexical cast - c++

Hey guys I have a question about my code. Here's what we have to do:
"Ask the user to read a file. The file will be in the same format as “items.txt” on the website. There will
always be a list of items with a name and price followed by some amount of recipes. If a recipe for an
item is not present, the only way to make the item is to buy it directly. Make a program that reads all
the items and recipes, then says how much profit can be made by making each item.
If an item has no recipe, you would buy that item then resell it for the same price and make a profit of
0. If an item does have a recipe, you would buy the materials to make this item and subtract this cost
from the price of the final product.
There will only be zero or one recipe per item. The items will always be listed first. The names of
items will always be a single word (using a _ to join names that are normally multiple words). You
may assume there will be less than 50 items and each recipe will use less than 50 other items to create a
final product."
This is the items1.txt we use
Item: Wood 2.5
Item: Metal 5.5
Item: Cat 900
Item: Spear 50.7
Recipe: Spear = Wood + Wood + Metal ;
I have what I think would work but I can't get a certain line to work. I'm trying to use stod but apparently my school's computers don't support it. I also tried boost lexical cast and that wouldn't work either.
It says "stod: was not declared in this scope.
Here's my code:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <algorithm>
#include <sstream>
using namespace std;
string nextstring(string str, int start_index);
int split(string str, string a[], int max_size);
int main()
{
ifstream in_stream;
string fileName;
cout << "Enter the file name : ";
cin >> fileName;
in_stream.open(fileName.c_str());
//error checking
if (in_stream.fail())
{
cout << "File could not be opened." << endl;
exit(1);
}
string items[50];
double items_value[50];
string recipe[50];
string rname = recipe[0];
double profit = 0;
int j = 0;
string lines;
int number_of_lines = 0;
while(getline(in_stream, lines))
{
if(lines.substr(0,5) == "Item:")
{
int beginning = lines.find_first_of(' ') + 1;
int next_space = lines.find(" ", beginning);
items_value[j] = stod(lines.substr(next_space));
items[j] = lines.substr(beginning,lines.find_first_of(' ', beginning) - beginning);
j++;
}
if(lines.substr(0,7) == "Recipe:")
{
int max_size = lines.length();
int cnt = split(lines,recipe,max_size);
double profit1 = 0;
double profit2 = 0;
for(int j = 3; j < cnt; j++)
{
for(int i = 0; i < 4; i++)
{
if((recipe[j] == items[i]) && (recipe[j] != "+")&& (recipe[j] != ";"))
{
cout << "Making " << items[i] << ", " << "profit = 0" << endl;
profit1 += items_value[i];
}
if(recipe[1] != items[i])
{
profit2 = 0;
}
}
}
for(int i = 0; i < cnt; i++)
{
if((recipe[1] == items[i]))
{
profit = items_value[i];
cout << "Making " << items[i] << ", " << "profit = ";
}
}
cout << profit - profit1 << endl;
}
}
in_stream.close();
return 0;
}
string nextstring(string str, int start_index)
{
int y =0;
y = str.find(' ',start_index);
y = y-start_index;
str = str.substr(start_index,y);
return str;
}
int split(string str, string a[], int max_size)
{
int i;
int num = 0;
for (i=0; i<max_size; i++)
{
a[i] = nextstring(str,num);
num = num + a[i].length() + 1;
if(num >= str.length())
{
i++;
break;
}
}
return i;
}

First step is get a decent compiler from this century ;) stod has been available since c++11, which really means that it was available probably a few years before that.
If stod isn't available to you then you can revert to the cstdlib function atof.

Related

"Expression cannot seek vector iterator after end "

I am trying to make a very simple memory game and i'm having the following problem with vectors.
Expression cannot seek vector iterator after end
here is my code
#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
using namespace std;
void play();
void filler();
char faceup(int);
vector<char> cards (50);
int candy= 0;
int main()
{
filler();
play();
}
char faceup(int C) {
return cards[C];
}
void play() {
int n,l;
char p, s;
for (int i = 0; i < cards.size(); i++)
{
cout << cards[i];
}
cout << endl;
while (candy<50)
{
cout << "choose first card"<<endl;
cin >> n;
cout << "choose second card"<<endl;
cin >> l;
if (l == n) {
cout << "the cards are the same, try it again"<<endl;
}
else
{
p = faceup(n);
s = faceup(l);
cout << "The first card is: " + p;
cout << "The second card is: " + s;
if (s==p)
{
candy++;
cards.erase(cards.begin()+s);
cards.erase(cards.begin() + p);
}
}
}
}
void filler() {
//random_device rd;
//default_random_engine rng(rd());
int accountant = 0;
for (int i = 0; i < cards.size()/2; i++)
{
for (int o = 0; o < 2; o++) {
cards[accountant] = i+65;
accountant++;
}
}
//shuffle(cards.begin(), cards.end(), rng);
}
the error occurs with any integer that I type. I used the compiler of visual studio, then i used dev c++. In all cases I got the same or similar error
Thanks a million in advance
In your code, in line 11, you defined a vector whose length is equal to 50, and if we give our vector a number outside the numbers 0 to 49, the program should not run.
That you encountered the error I mentioned above in lines 48 and 49 of your program.
For example, if the user enters his card number 0 and 1, the sizes s and p are equal to 66, and lines 48 and 49 say to go to our vector index 66, which creates a problem for running our program.
enter code here
//////////error/////////////////////////
cards.erase(cards.begin()+s);
cards.erase(cards.begin() + p);
//////////error/////////////////////////

How do I remove repeated words from a string and only show it once with their wordcount

Basically, I have to show each word with their count but repeated words show up again in my program.
How do I remove them by using loops or should I use 2d arrays to store both the word and count?
#include <iostream>
#include <stdio.h>
#include <iomanip>
#include <cstring>
#include <conio.h>
#include <time.h>
using namespace std;
char* getstring();
void xyz(char*);
void tokenizing(char*);
int main()
{
char* pa = getstring();
xyz(pa);
tokenizing(pa);
_getch();
}
char* getstring()
{
static char pa[100];
cout << "Enter a paragraph: " << endl;
cin.getline(pa, 1000, '#');
return pa;
}
void xyz(char* pa)
{
cout << pa << endl;
}
void tokenizing(char* pa)
{
char sepa[] = " ,.\n\t";
char* token;
char* nexttoken;
int size = strlen(pa);
token = strtok_s(pa, sepa, &nexttoken);
while (token != NULL) {
int wordcount = 0;
if (token != NULL) {
int sizex = strlen(token);
//char** fin;
int j;
for (int i = 0; i <= size; i++) {
for (j = 0; j < sizex; j++) {
if (pa[i + j] != token[j]) {
break;
}
}
if (j == sizex) {
wordcount++;
}
}
//for (int w = 0; w < size; w++)
//fin[w] = token;
//cout << fin[w];
cout << token;
cout << " " << wordcount << "\n";
}
token = strtok_s(NULL, sepa, &nexttoken);
}
}
This is the output I get:
I want to show, for example, the word "i" once with its count of 5, and then not show it again.
First of all, since you are using c++, I would recommend you to split text in c++ way(some examples are here), and store every word in map or unordered_map. Example of my realization you can find here
But if you don't want to rewrite your code, you can simply add a variable that will indicate whether a copy of the word was found before or after the word position. If a copy was not found in front, then print your word
This post gives an example to save each word from your 'strtok' function into a vector of string. Then, use string.compare to have each word compared with word[0]. Those indexes match with word[0] are marked in an int array 'used'. The count of match equals to the number marks in the array used ('nused'). Those words of marked are then removed from the vector, and the remaining carries on to the next comparing process. The program ends when no word remained.
You may write a word comparing function to replace 'str.compare(str2)', if you prefer not to use std::vector and std::string.
#include <iostream>
#include <string>
#include <vector>
#include<iomanip>
#include<cstring>
using namespace std;
char* getstring();
void xyz(char*);
void tokenizing(char*);
int main()
{
char* pa = getstring();
xyz(pa);
tokenizing(pa);
}
char* getstring()
{
static char pa[100] = "this is a test and is a test and is test.";
return pa;
}
void xyz(char* pa)
{
cout << pa << endl;
}
void tokenizing(char* pa)
{
char sepa[] = " ,.\n\t";
char* token;
char* nexttoken;
std::vector<std::string> word;
int used[64];
std::string tok;
int nword = 0, nsize, nused;
int size = strlen(pa);
token = strtok_s(pa, sepa, &nexttoken);
while (token)
{
word.push_back(token);
++nword;
token = strtok_s(NULL, sepa, &nexttoken);
}
for (int i = 0; i<nword; i++) std::cout << word[i] << std::endl;
std::cout << "total " << nword << " words.\n" << std::endl;
nsize = nword;
while (nsize > 0)
{
nused = 0;
tok = word[0] ;
used[nused++] = 0;
for (int i=1; i<nsize; i++)
{
if ( tok.compare(word[i]) == 0 )
{
used[nused++] = i; }
}
std::cout << tok << " : " << nused << std::endl;
for (int i=nused-1; i>=0; --i)
{
for (int j=used[i]; j<(nsize+i-nused); j++) word[j] = word[j+1];
}
nsize -= nused;
}
}
Notice that the removal of used words has to do in backward order. If you do it in sequential order, the marked indexes in the 'used' array will need to be changed. A running test:
$ ./a.out
this is a test and is a test and is test.
this
is
a
test
and
is
a
test
and
is
test
total 11 words.
this : 1
is : 3
a : 2
test : 3
and : 2
I read your last comment.
But I am very sorry, I do not know C. So, I will answer in C++.
But anyway, I will answer with the C++ standard approach. That is usually only 10 lines of code . . .
#include <iostream>
#include <algorithm>
#include <map>
#include <string>
#include <regex>
// Regex Helpers
// Regex to find a word
static const std::regex reWord{ R"(\w+)" };
// Result of search for one word in the string
static std::smatch smWord;
int main() {
std::cout << "\nPlease enter text: \n";
if (std::string line; std::getline(std::cin, line)) {
// Words and its appearance count
std::map<std::string, int> words{};
// Count the words
for (std::string s{ line }; std::regex_search(s, smWord, reWord); s = smWord.suffix())
words[smWord[0]]++;
// Show result
for (const auto& [word, count] : words) std::cout << word << "\t\t--> " << count << '\n';
}
return 0;
}

How to use selection sort on string vector of objects

I pretty new to coding and a lot of things are pretty foreign to me. I am writing a c++ program that is supposed to take a list of songs from a txt file and be able to shuffle, sort, and search for a song in the list. I have only started on the sorting part as of now, but I am having trouble finding out how to format the algorithm to work with my vector of songs.
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdlib>
#include <time.h>
#include <stdlib.h>
#include <bits/stdc++.h>
#include <algorithm>
#include "song.h"
using namespace std;
// given to you
void processFile(vector<Song> &playlist);
// you should create
void shuffle(vector<Song> &playlist);
void bubbleSort(vector<Song> &playlist);
void displayPlaylist(vector<Song> playlist);
int binarySearch(vector<Song> &playlist, string songTitle);
int main()
{
vector<Song> playlist;
// sets up playlist
processFile(playlist);
cout << "\nInitial playlist: " << endl;
//displayPlaylist(playlist);
displayPlaylist(playlist);
cout << "Welcome to the playlist display manager." << endl << endl;
while(1)
{
int option;
cout << "0. Exit" << endl;
cout << "1. Sort Playlist" << endl;
cout << "2. Shuffle Playlist" << endl;
cout << "3. Search Playlist" << endl;
cout << "Which option would you like" << endl;
cin >> option;
if(option == 0)
{
break;
}
else if(option == 1)
{
bubbleSort(playlist);
displayPlaylist(playlist);
}
else if(option == 2)
{
}
else if(option == 3)
{
}
else
{
cout << "invalid response...try again" << endl;
}
}
return 0;
}
void processFile(vector<Song> &playlist)
{
ifstream infile;
string line;
infile.open("songs.txt");
if(infile.is_open())
{
cout << "Successful songs opening." << endl;
}
else
{
cout << "Couldn't locate file. Program closing." << endl;
exit(EXIT_FAILURE);
}
while(getline(infile, line))
{
// first line --> song
// second line --> artist
if(line != "")
{
string song, artist;
song = line;
getline(infile, artist);
Song temp(song, artist);
playlist.push_back(temp);
}
}
return;
}
void shuffle(vector<Song> &playlist)
{
}
void selectionSort(vector<Song> &playlist, int n)
{
}
void bubbleSort(vector<Song>& playlist)
{
int size;
size = playlist.size();
for(int i= 0; i < size - 1; i++)
{
int smallIndex = i;
for(int j = i + 1; j < size; j++)
{
if(&playlist[j] < &playlist[smallIndex])
{
smallIndex = j;
}
}
string song, artist;
Song temp(song, artist);
temp = playlist[i];
playlist[i] = playlist[smallIndex];
playlist[smallIndex] = temp;
}
}
//display songs
void displayPlaylist(vector<Song> playlist)
{
for(int i = 0; i < playlist.size(); i++)
{
cout << playlist[i].getTitle() << " - " << playlist[i].getArtist() << endl;
}
}
Here is what I have so far. I am supposed to use a function to sort the sort the songs. The vector uses a class that was given to me to help classify the line of songs in the txt file by song then artist (title being the first thing listed in the line) and I'm supposed to sort by the title. This is just the last algorithm I attempted. I'm not required to use selection sorting. Whenever I call the function and try to display the list, it comes out the same.
edit: Sorry, it just occurred that I should probably go ahead and show all my code even if it's not done.
Your sorting algorithm is almost correct with small mistake .
You need to drop the & in if condition of your nested loop , you inner loop should be as follows ,
for(int j = i + 1; j < size; j++)
{
if(playlist[j] < playlist[smallIndex])
{
smallIndex = j;
}
}
Though this being said , since playlist is vector of Song objects , and you are using < operator on these objects , you will need to overload less-than < operator for your class . On the other hand , if you need to sort by song name or artist name , and they are well defined C++ objects(since most C++ library objects have already defined less-than operator for them) . For instance if song name or artist name are strings , and you need to sort by , let's say song name , then you can do it like this ,
if(playlist[j].song_name < playlist[smallIndex].song_name)
Here , you don't need to prefix the variable by ampersand & , you might be getting confused due to using ampersand with the variable playlist in function parameter list . Well , ampersand there is to tell the compiler to pass the variable as reference . For more information regarding reference variables , read the following links ,
What is reference variable in C++ and Reference variables

Sorting multiple arrays of different types from a read file

I'm working on a program that mimics an "Animal Adoption Agency." I read from the file, which contains a list of animal names, breed, age, price, and sex. I have two files, one each for cats and dogs.
The user has an option to sort the list by the above listed categories. I have a for loop currently that will accurately sort the category they choose; however, the other categories will not order themselves accordingly. I'm not sure how to go about this.
Here's a condensed version of my code, that allows access only to the dogs portion and sorting by name, rather than have a choice of how to sort.
#include <iostream>
#include <fstream>
#include <istream>
#include <cctype>
#include <string>
#include <string.h>
#include <cstring>
#include <iomanip>
#include <vector>
#include <algorithm>
using namespace std;
int animalMenu, animalCount, animAge[50], animPrice[50], entry = 0, total;
string animType, animName[50], animBreed[50], animSex[50], takeHomeWith;
ifstream animalInform;
const int WIDTH = 8, BIG_WIDTH = 12;
void sortingHat(string[]);
void innerSorting(string[], int);
int main() {
animalInform.open("Dog Information.txt");
animType = "dogs";
// SET NUMBER OF ANIMALS IN FILE
animalInform >> animalCount;
cout << "There are " << animalCount << " " << animType << "! \n";
// SETS ALL THE VALUES BY READING FROM FILE
for (int entry = 0; entry < animalCount; entry++) {
animalInform >> animName[entry] >> animBreed[entry] >> animAge[entry] >> animPrice[entry] >> animSex[entry];
cout << setw(BIG_WIDTH) << animName[entry] << setw(BIG_WIDTH) << animBreed[entry] << setw(WIDTH) << animAge[entry] << setw(WIDTH) << animPrice[entry] << setw(WIDTH) << animSex[entry] << endl;
}
// CLOSE FILE
animalInform.close();
// CALL FUNCTION TO SORT (BY NAME ONLY)
sortingHat(animName);
cout << endl;
// DISPLAY NEWLY SORTED LIST
for (int entry = 0; entry < animalCount; entry++) {
cout << setw(BIG_WIDTH) << animName[entry] << setw(BIG_WIDTH) << animBreed[entry] << setw(WIDTH) << animAge[entry] << setw(WIDTH) << animPrice[entry] << setw(WIDTH) << animSex[entry] << endl;
}
system("pause");
}
void sortingHat(string sortingString[])
{ // SORTS DATA AND PUTS IT IN ORDER, ALPHABETICAL --
for (int outer = 0; outer <= animalCount; outer++)
{
for (int entry = 0; entry <= (animalCount - 2); entry++) {
string temporary[50];
if (sortingString[entry] > sortingString[entry + 1])
innerSorting(sortingString, entry);
}
}
}
void innerSorting(string sorter[], int entry)
{
string temporary[50];
temporary[entry] = sorter[entry];
sorter[entry] = sorter[entry + 1];
sorter[entry + 1] = temporary[entry];
}
So I obviously don't have anything that would make the other entries follow suit.
So if I choose name to be sorted, my output (this is what is written in my file) will go from
Brienne Shepard 6 $150 F
Jon Labrador 3 $200 M
Aemon ShihTzu 10 $50 M
to
Aemon Shepard 6 $150 F
Brienne Labrador 3 $200 M
Jon ShihTzu 10 $50 M
And I want it to do this (if choosing to sort by name):
Aemon ShihTzu 10 $50 M
Brienne Shepard 6 $150 F
Jon Labrador 3 $200 M
If I have understood you correctly you have a set of arrays that contain animal characteristics. And you are going to sort by one characteristics such a way that all arrays would be sorted. If so then you can write one common function for all arrays.
For example
enum SortType { SortByName, /* other types of sorting */, SortByAge };
//...
void bubble_sort( std::string animName[],
/* other characteristics */
int animAge[],
size_t n,
SortType type )
{
for ( size_t last; not ( n < 2 ); n = last )
{
for ( size_t i = last = 1; i < n; i++ )
{
bool less = false;
switch ( type )
{
case SortByName:
less = animName[i] < animName[i-1];
break;
/* other cases */
case SortByAge:
less = animAge[i] < animAge[i-1];
break;
}
if ( less )
{
/* swapping elements of all the arrays */
last = i;
}
}
}
}
Take into account that this swap function
void innerSorting(string sorter[], int entry)
{
string temporary[50];
^^^^^^^^^^^^^^^^^^^^
temporary[entry] = sorter[entry];
sorter[entry] = sorter[entry + 1];
sorter[entry + 1] = temporary[entry];
}
should not use an array of strings. It can be written like
void innerSorting(string sorter[], size_t entry)
{
string temporary;
^^^^^^^^^^^^^^^^^
temporary = sorter[entry];
sorter[entry] = sorter[entry + 1];
sorter[entry + 1] = temporary;
}

C++ recursive permutation algorithm for strings -> not skipping duplicates

I'm having trouble finding a simple statement to skip the duplicates for this recursive permutation code. I've looked everywhere and seem to only find examples using swap or java. From what I gather, I think I need to put a line right after the for-loop.
Thank you!
#include "genlib.h"
#include "simpio.h"
#include <string>
#include <iostream>
void ListPermutations(string prefix, string rest);
int main() {
cout << "Enter some letters to list permutations: ";
string str = GetLine();
cout << endl << "The permutations are: " << endl;
ListPermutations("", str);
return 0;
}
void ListPermutations(string prefix, string rest)
{
if (rest == "")
{
cout << prefix << endl;
}
else
{
for (int i = 0; i < rest.length(); i++)
{
if (prefix != "" && !prefix[i]) continue; // <--- I tried adding this, but it doesn't work
cout << endl<< "prefix: " << prefix << " | rest: " << rest << endl;
string newPrefix = prefix + rest[i];
string newRest = rest.substr(0, i) + rest.substr(i+1);
ListPermutations(newPrefix, newRest);
}
}
}
this should work :
your algoithm is good, i only added a test : if a unique char is already used at a position. if yes, no more permutation is made because all permutations with that char in that position is already made.
void ListPermutations(string prefix, string rest)
{
if (rest == "")
{
cout << prefix << endl;
}
else
{
for (int i = 0; i < rest.length(); i++)
{
//test if rest[i] is unique.
bool found = false;
for (int j = 0; j < i; j++)
{
if (rest[j] == rest[i])
found = true;
}
if(found)
continue;
string newPrefix = prefix + rest[i];
string newRest = rest.substr(0, i) + rest.substr(i+1);
ListPermutations(newPrefix, newRest);
}
}
}
you can also sort the string before making permutations, the result will be the same.
In C++ to generate permutation use std::next_permutation
It will handle duplicate entries just fine and do the right thing
Ignoring the availability of std::next_permutation, because your comment on the previous answer...
If you want to generate all the unique permutations, you're going to need to have them in order at some point. The hackiest way to do this would be to put them all in a vector, sort it and then suppress duplicate adjacent entries when printing it out. But that's a lot slower than it needs to be.
You'll need to start with by sorting your string, so that identical permutations will be generated after each other. Then in your for loop, make sure you skip any duplicate letters in 'rest'. something like:
char lastAdditionToPrefix = '\0';
for (int i = 0; i < rest.length(); i++)
{
if (rest[i] == lastAdditionToPrefix) continue;
lastAdditionToPrefix = rest[i];
cout << endl<< "prefix: " << prefix << " | rest: " << rest << endl;
...
I'm not convinced that this change will completely fix your code, but it's closer than you are at the moment. edit: this, plus sorting the input in main(), will work
Tested and works fine. The idea is for each stack level, at location i, remember whether a character has been at that location already.
using namespace std;
void doPermutation(vector<char> &input, int index) {
bool used[26] = {false};
if(index == input.size()) {
copy(input.begin(), input.end(), ostream_iterator<char>(cout, "") );
cout << endl;
} else {
int i, j;
for(i =index; i < input.size(); i++ ) {
if(used[ input[i]-'a'] == false) {
swap(input[i], input[index]);
doPermutation(input, index+1);
swap(input[i], input[index]);
used[input[i]-'a'] = true;
}
}
}
}
void permutation(vector<char>& input) {
doPermutation(input, 0);
}
int main()
{
cout << "Hello World" << endl;
const char* inp = "alla";
vector<char> input(inp, inp + 4 );
permutation(input);
return 0;
}
The different for algorithms with or without duplicate would be when you swap it, make sure that the character that you want to swap has not been swapped before. Use hash map to keep track of what you have swapped before.
See the C# code below.
private void PermuteUniqueHelper(int[] nums, int index, List<IList<int>> res)
{
var used = new Dictionary<int, bool>();
if (index == nums.Length)
{
res.Add(new List<int>(nums));
return;
}
for (int i = index; i < nums.Length; i++)
{
if (!used.ContainsKey(nums[i]))
{
swap(nums[i], nums[index]);
this.PermuteUniqueHelper(nums, index + 1, res);
swap(nums[i], nums[index]);
used.Add(nums[i], true);
}
}
}