Related
Is there a way to loop this so I don't have to write it out 10 times?
Basically, I'm creating instances for a DVD class which each has different member values. It would be nice if I could make my file more readable. I've got this far.
for (int i=n; i<= 10; i++) {
for (int j=0; j<=9; j++) {
if (n == i) {
dvd[j].print();
}
}
}
but it's obviously wrong and I know why to. I just don't know if it's possible.
DVD dvd[10];
dvd[0].id = d[2];
dvd[0].name = d[3];
dvd[0].genre = d[4];
dvd[0].cast = d[5];
dvd[0].desc = d[6];
dvd[0].dateRent = d[7];
dvd[0].dateRet = d[8];
dvd[0].cost = d[9];
dvd[1].id = d[12];
dvd[1].name = d[13];
dvd[1].genre = d[14];
dvd[1].cast = d[15];
dvd[1].desc = d[16];
dvd[1].dateRent = d[17];
dvd[1].dateRet = d[18];
dvd[1].cost = d[19];
dvd[2].id = d[22];
dvd[2].name = d[23];
dvd[2].genre = d[24];
dvd[2].cast = d[25];
dvd[2].desc = d[26];
dvd[2].dateRent = d[27];
dvd[2].dateRet = d[28];
dvd[2].cost = d[29];
dvd[3].id = d[32];
dvd[3].name = d[33];
dvd[3].genre = d[34];
dvd[3].cast = d[35];
dvd[3].desc = d[36];
dvd[3].dateRent = d[37];
dvd[3].dateRet = d[38];
dvd[3].cost = d[39];
dvd[4].id = d[42];
dvd[4].name = d[43];
dvd[4].genre = d[44];
dvd[4].cast = d[45];
dvd[4].desc = d[46];
dvd[4].dateRent = d[47];
dvd[4].dateRet = d[48];
dvd[4].cost = d[49];
dvd[5].name = d[53];
dvd[5].id = d[52];
dvd[5].genre = d[54];
dvd[5].cast = d[55];
dvd[5].desc = d[56];
dvd[5].dateRent = d[57];
dvd[5].dateRet = d[58];
dvd[5].cost = d[59];
dvd[8].id = d[62];
dvd[8].name = d[63];
dvd[8].genre = d[64];
dvd[8].cast = d[65];
dvd[8].desc = d[66];
dvd[8].dateRent = d[67];
dvd[8].dateRet = d[68];
dvd[8].cost = d[69];
dvd[7].id = d[72];
dvd[7].name = d[73];
dvd[7].genre = d[74];
dvd[7].cast = d[75];
dvd[7].desc = d[76];
dvd[7].dateRent = d[77];
dvd[7].dateRet = d[78];
dvd[7].cost = d[79];
dvd[8].id = d[82];
dvd[8].name = d[83];
dvd[8].genre = d[84];
dvd[8].cast = d[85];
dvd[8].desc = d[86];
dvd[8].dateRent = d[87];
dvd[8].dateRet = d[88];
dvd[8].cost = d[89];
dvd[9].id = d[92];
dvd[9].name = d[93];
dvd[9].genre = d[94];
dvd[9].cast = d[95];
dvd[9].desc = d[96];
dvd[9].dateRent = d[97];
dvd[9].dateRet = d[98];
dvd[9].cost = d[99];
and
if (n == 1) {
dvd[0].print();
}
if (n == 2) {
dvd[1].print();
}
if (n == 3) {
dvd[2].print();
}
if (n == 4) {
dvd[3].print();
}
if (n == 5) {
dvd[4].print();
}
if (n == 6) {
dvd[5].print();
}
if (n == 7) {
dvd[6].print();
}
if (n == 8) {
dvd[7].print();
}
if (n == 9) {
dvd[8].print();
}
if (n == 10) {
dvd[9].print();
}
eglease's comment was spot on: You'll notice that the index you want to print is one smaller than your n (wherever that comes form), so you can simply use n-1 as an index to print. That is, I think, what you tried to achieve with your nested loop and did with your if-chain, but you were thinking too complicated: No loop is required! You could have spotted the connection between n and the array index when you wrote the if-chain: The index is always one smaller than the n. You can simply write that ;-).
void print dvd_number_n(int n) { dvd[n-1].print(); }
If you want to loop over all your DVDs you can loop from 0 to n-1, which is very common in C or C++ because it has zero-based arrays, that is, the first element is at index 0.
The idiomatic way to code that is a for loop starting at 0 and testing the loop variable for being truly smaller than the number of elements.
For an array with 3 DVDs array alements would be dvd[0], dvd[1], and dvd[2]. dvd[3] would be out-of-bounds, because there are only 3 elements in the array, not 4. Such boundary violations are one of the most common errors in C or C++ which do not check array indices (and typically can't do that at all because the array size is unknown at the site of use). The print loop for an array of 3 DVDs would be
for( int i=0; i<3; i++) { dvd[i].print(); }
The index i
starts with 0, execute loop (1)
is incremented to 1, smaller than 3, execute loop (2)
is incremented to 2, smaller than 3, execute loop (3)
is incremented to 3, equal to 3, loop condition is false, loop is left.
This gives us the 3 loop executions with the indices 0,1,2 as desired.
There is a lot of room for improvement: Give your class a constructor and use a vector, not an array. Here is an example that may give you an idea.
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
/// A simple data holder for DVD information with a constructor.
class DVD_T
{
std::string mTitle;
unsigned int mCost; // in cent
public:
DVD_T(std::string title, unsigned int cost): mTitle(title), mCost(cost) {}
void print(std::ostream &os)
{
os << "Title: \"" << mTitle
<< "\", cost: $" << mCost/100 << "." << std::setw(2) << std::setfill('0') << mCost%100;
}
};
std::vector<DVD_T> &initDVDs()
{
// This initialization of a static local variable will be run only once.
static std::vector<DVD_T> DVDs
{
// You'll probably want to obtain data from your data array d.
{"Title 1", 109},
{"Title 2", 99}
};
return DVDs;
}
int main()
{
// Get reference to initialized vector of DVDs
std::vector<DVD_T> &DVDs = initDVDs();
// Print them all. "Look mama, no index!"
for(auto dvd: DVDs)
{
dvd.print(std::cout);
std::cout << '\n';
}
}
Output:
Title: "Title 1", cost: $1.09
Title: "Title 2", cost: $0.99
My vector of strings with dynamic size based of what user wants
std::vector<std::string>* allTags = new std::vector<std::string>[tvSize];
Filling the allTags variable
for (unsigned int i = 0; i < tvSize; i++)
allTags[i] = ParseData(vals[i]);
Now suppose that size of allTags pointer is 3 and following are the values in each:-
allTags[0] = { "0", "1", "2"}
allTags[1] = { "a", "b", "c"}
allTags[2] = { "X", "Y", "Z"}
I want to combine the data of all 3 allTags in vector of string say combined_data. But I want to do it in the following way:-
combined_data[0] = "0->a->X"; combined_data[1] = "0->a->Y"; combined_data[2] = "0->a->Z";
combined_data[3] = "0->b->X"; combined_data[4] = "0->b->Y"; combined_data[5] = "0->b->Z";
combined_data[6] = "0->c->X"; combined_data[7] = "0->c->Y"; combined_data[8] = "0->c->Z";
combined_data[9] = "1->a->X"; combined_data[10] = "1->a->Y"; combined_data[11] = "1->a->Z";
And so on. But I'm not able to come up with an algorithm for this. Can anyone help?
You want something like this:
vector<string> function(int lvl)
{
if (lvl == tvSize) return vector<string>(0);
vector<string> r; // some compilers will complain because of ()
vector<string> v = funtion(lvl + 1);
for(int i = 0; i < allTags[lvl].size(); i++)
{
if (v.size() != 0)
{
for(int k = 0; k < v.size(); k++)
{
string result = allTags[lvl][i];
//result += new string("->").append(v[k]); - memory leak
string pom("->");
result += pom.append(v[k]);
r.push_back(result);
}
}
else{ r.push_back(allTags[lvl][i]); }
}
return r;
}
Read std::vector documentation.
What you want is all permutations on every level, so complexity is O(n^(r + 1)), where n is number of elements in every row and r is tvSize in your example, and you can't do much about that, but if you don't need every permutation you could exclude some element on any level of recursion. So if you don't need permutations with 'c' your algorithm will be faster for O(n^(r + 1 - l)), where l is level of 'c'.
I've been recently working on a project which includes a Rubik's Cube scramble generator. Basically the program should generate and display random cube notations so that the user can follow each move and have a fairly scrambled cube. Notations include "R" for turning the right layer , "L" for turning the left layer, "F" for turning front layer, "D" for down, "U" for up and "B" for back. And so you have a total of 6 sides "R, L, U, D, F, B". The appostrophe after any of these notations means moving that layer counter clockwise and "2" means moving that layer twice. The problem is you can't have the same notation be repeated next to each other like "R, R" as it would be the same as "R2", nor you can have "R, R' " next to each other as they would cancel each other out. My solution to this was making a 2 dimensional array for storing the 3 groups of notations for every type.
string notation_group[row][column] = { { "R ", "L ", "F ", "B ", "U ", "D " },
{"R' ", "L' ", "F' ", "B' ", "U' ", "D' "}, { "R2", "L2", "F2", "B2", "U2", "D2"} };
This means that whenever the program picks a random column from any of these groups, the program has to prevent the next generated notation from choosing the same column in any other group. So let's say if the program picks the first element of the first group "R", then for the next iteration it can choose any notation except "R", "R' " and "R2", all of which belong to the first column of their respective groups. So all the program has to do is not to pick that column during the next iteration.
I used a "temp" variable to keep in mind the current randomly generated notation and compare it to the next one, and generating a new one whenever those are equal.
int temp;
scrambled_notation[i] = notation_group[pickGroup][pickColumn];
temp = pickColumn;
pickColumn = 0 + rand() % 6;
while (temp == pickColumn) {
pickColumn = 0 + rand() % 6;
}
It does work but there is still another problem, whenever you have something like "R, L" or "R, L', R" be repeated multiple times next to each other they would again cancel each other out leaving no affect on the cube. Is there any idea for how can I prevent two of the opposing sides being repeated next to each other for more than once? I would greatly appreciate the help.
void initScramble(const int, string[][6], string[]);
int main() {
srand(time(0));
const int row = 3, column = 6;
string notation_group[row][column] = { { "R", "L", "F", "B", "U", "D" },
{"R'", "L'", "F'", "B'", "U'", "D'"}, { "R2", "L2", "F2", "B2", "U2", "D2"} };
const int scrambleSize = 22;
string scrambled_notation[scrambleSize];
cout << "SCRAMBLE: " << endl;
initScramble(scrambleSize, notation_group, scrambled_notation);
system("pause");
return 0;
}
void initScramble(const int scrambleSize, string notation_group[][6], string scrambled_notation[]) {
int pickColumn = 0 + rand() % 6;
while (true) {
cin.get();
for (int i = 0; i < scrambleSize; i++) {
int pickGroup = 0 + rand() % 3;
int temp;
scrambled_notation[i] = notation_group[pickGroup][pickColumn];
temp = pickColumn;
pickColumn = 0 + rand() % 6;
while (temp == pickColumn) {
pickColumn = 0 + rand() % 6;
}
}
for (int i = 0; i < scrambleSize; i++) {
cout << scrambled_notation[i] << " ";
}
cin.get();
system("CLS");
}
}
You have to look for the last two moves as long as they are commutative. If not, then you only check for the last move. This is simplified by the fact that each pair of columns are commutative:
void initScramble(const int scrambleSize, string notation_group[][6], string scrambled_notation[]) {
while (true) {
int lastColumn = 7; // Invalid columns
int beforeLastColumn = 7;
cin.get();
for (int i = 0; i < scrambleSize; i++) {
int pickGroup = 0 + rand() % 3;
int pickColumn = 0 + rand() % 6;
bool isCommutative = (lastColumn / 2) == (beforeLastColumn / 2);
while (pickColumn == lastColumn || isCommutative && pickColumn == beforeLastColumn) {
pickColumn = 0 + rand() % 6;
}
scrambled_notation[i] = notation_group[pickGroup][pickColumn];
beforeLastColumn = lastColumn;
lastColumn = pickColumn;
}
for (int i = 0; i < scrambleSize; i++) {
cout << scrambled_notation[i] << " ";
}
cin.get();
system("CLS");
}
}
You don't have to look further since you can have only 2 commutative consecutive moves following your rules of scrambling. For example, 'L,R,L' and 'L,R,R' will be discarded, and thus, 3 commutative moves will never be generated.
I'm creating a program that creates an array of objects in random positions in an array size 8. Once created, I need them to sort so that all the objects in the array are shifted up to the top, so no gaps exist between them. I'm almost there, but I cannot seem to get them to swap to index 0 in the array, and they instead swap to index 1. Any suggestions? (Must be done the way I'm doing it, not with other sorting algorithms or whatnot)
#include <iostream>
#include <string>
#include <ctime>
using namespace std;
struct WordCount {
string name = "";
int count = 0;
};
int main() {
cout << "Original random array: " << endl;
srand(static_cast<int>(time(0)));
int i = 0;
WordCount wordArr[8];
while (i < 4) {
int randomNum = 0 + (rand() % static_cast<int>(7 + 1));
if(wordArr[randomNum].name == "") {
wordArr[randomNum].name = "word" + static_cast<char>(i);
wordArr[randomNum].count = i;
i++;
}
}
int j = 0;
while (j < 8) {
cout << wordArr[j].name << " " << wordArr[j].count << endl;
j++;
}
cout << "\n\nSorted array: " << endl;
for (int i = 7; i >= 0; i--) {
for (int j = 0; j <= 7; j++) {
if (wordArr[i].name != "") {
if (wordArr[j].name == "") {
WordCount temp = wordArr[i];
wordArr[i] = wordArr[j];
wordArr[j] = temp;
}
}
}
}
int k = 0;
while (k < 8) {
cout << wordArr[k].name << " " << wordArr[k].count << endl;
k++;
}
return 0;
}
If I understand your requirement correctly, you want to move all the non-blank entries to the start of the array. To do this, you need an algorithm like this for example:
for i = 0 to 7
if wordArr[i].name is blank
for j = i + 1 to 7
if wordArr[j].name is not blank
swap [i] and [j]
break
So, starting from the beginning, if we encounter a blank entry, we look forward for the next non-blank entry. If we find such an entry, we swap the blank and non-blank entry, then break to loop again looking for the next blank entry.
Note, this isn't the most efficient of solutions, but it will get you started.
Note also I'd replace the 4 and 8 with definitions like:
#define MAX_ENTRIES (8)
#define TO_GENERATE_ENTRIES (4)
Finally:
wordArr[randomNum].name = "word" + static_cast<char>(i);
That will not do what you want it to do; try:
wordArr[randomNum].name = "word" + static_cast<char>('0' + i);
To append the digits, not the byte codes, to the end of the number. Or perhaps, if you have C++11:
wordArr[randomNum].name = "word" + std::to_string(i);
I see couple of problems.
The expression "word" + static_cast<char>(i); doesn't do what you are hoping to do.
It is equivalent to:
char const* w = "word";
char const* p = w + i;
When i is 2, p will be "rd". You need to use std::string("word") + std::to_string(i).
The logic for moving objects with the non-empty names to objects with empty names did not make sense to me. It obviously does not work for you. The following updated version works for me:
for (int i = 0; i <= 7; ++i) {
// If the name of the object at wordArr[i] is not empty, move on to the
// next item in the array. If it is empty, copy the next object that
// has a non-empty name.
if ( wordArr[i].name == "") {
// Start comparing from the object at wordArr[i+1]. There
// is no need to start at wordArr[i]. We know that it is empty.
for (int j = i+1; j <= 7; ++j) {
if (wordArr[j].name != "") {
WordCount temp = wordArr[i];
wordArr[i] = wordArr[j];
wordArr[j] = temp;
}
}
}
}
There was two problems as :
wordArr[randomNum].name = "word" + static_cast<char>(i); this is not what your are looking for, if you want that your names generate correctly you need something like this :
wordArr[randomNum].name = "word " + std::to_string(i);
Your sorting loop does not do what you want, it's just check for the "gaps" as you said, you need something like this :
for (int i = 0; i < 8; ++i) {
for (int j = i+1; j < 8; ++j) {
if (wordArr[i].name == "" || (wordArr[i].count < wordArr[j].count)) {
WordCount temp = wordArr[i];
wordArr[i] = wordArr[j];
wordArr[j] = temp;
}
}
}
Your algorithm sorts the array, but then looses the sorting again.
You want to swap elements only when i > j, in order to push elements to the top only. As a result, you need to change this:
if (wordArr[j].name == "")
to this:
if (wordArr[j].name == "" && i > j)
Consider this array example:
0
ord 1
0
0
rd 2
word 0
d 3
0
Your code will sort it to:
d 3
ord 1
word 0
rd 2
0
0
0
0
but when i = 3, it will try to populate the 5th cell, and it will swap it with rd 2, which is not what we want.
This will push rd 2 down, but we don't want that, we want gaps (zeroes) to go to the end of the array, thus we need to swap eleemnts only when they are going to go higher, not lower, which is equivalent to say when i > j.
PS: If you are a beginner skip that part.
You can optimize the inner loop by using one if statement and a break keyword, like this:
for (int j = 0; j <= 7; j++) {
if (wordArr[i].name != "" && wordArr[j].name == "" && i > j) {
WordCount temp = wordArr[i];
wordArr[i] = wordArr[j];
wordArr[j] = temp;
break;
}
}
I've been trying to put the total income calculated for that particular day into an array. So that at the end so that I can later total all the values in the array for a grand total.
I've got 2 arrays so far that have the demand for pies and number of apples picked. To calculate the income from pies, apple trays and total income for that day I've put it into a for loop.
So far I've got this: (this is for inputting the calculated value in the array)
float total[30];
int i, incmPie, numPie, rApples, applesLeft, FTray, incmFTray, PFTray;
float totalincm, incmApples, incmRApples, incmPFTray, totalincome;
**float total[30];**
int pieDemand[30]={4, 4, 2, 7, 1, 6, 7, 8, 9, 12, 2,13,13, 5, 3, 9, 9, 9, 8, 7,
12, 1, 3, 3,10,12, 3, 6, 9, 3};
int applesPicked[30]={330,123,110,245,321,999,0,100,77,89,100,200,300,390,700,20,701,6,800,90,
600,45,690,700,719,790,800,1000,66,666};
int date[30] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30};
printf("\n==============================================================================");
printf("\n Date Income from Pie Income from Apples Total income");
printf("\n==============================================================================");
for (i = 0 ; i <30; i++)
{
if (applesPicked[i] == 0)
{
incmPie = 0;
incmApples = 0;
totalincm = 0;
**total[i] = totalincm;**
}
else if (applesPicked[i] < (pieDemand[i]*8))
{
numPie = applesPicked[i]/8;
incmPie = numPie * 14;
rApples = applesPicked[i]%8;
incmRApples = rApples * 0.5;
incmApples = incmRApples;
totalincm = incmPie + incmRApples;
**total[i] = totalincm;**
}
else
{
incmPie = pieDemand[i] * 14;
applesLeft = applesPicked[i] - (pieDemand[i]*8);
FTray = applesLeft/20;
incmFTray = FTray * 12;
PFTray = applesLeft%20;
incmPFTray = PFTray * 0.5;
incmApples = incmFTray + incmPFTray;
totalincm = incmApples + incmPie;
**total[i] = totalincm;**
}
**totalincome** = total[1] + total[2] + total[3] + total[4] + total[5] + total[6] + total[7] + total[8] + total[9] + total[10] + total[11] + total[12] + total[13] + total[14] + total[15] + total[16] + total[17] + total[18] + total[19] + total[20] + total[21] + total[22] + total[23] + total[24] + total[25] + total[26] + total[27] + total[28] + total[29] + total[30];
printf("\n"); //prints onto the next line.
printf("%d/04/2013",date[i]); // prints the date.
printf("%15d", incmPie); // prints the income from pies for each value in the arrays.
printf("%20g", incmApples); // prints the income from apples from both full trays and remaining apples for each value in the arrays.
printf("%28g", totalincm);
}
printf("\n==============================================================================");
**printf("\n Total income for the entire month: $%g", totalincome);**
printf("\n------------------------------------------------------------------------------");
_getch();
}
and i'm using this code to sum the total of the array:
totalincome = total[1] + total[2] + ... + total[30];
Any help will be appreciated! :)
In C++ (almost all programming languages), array index starts at 0, not 1! Check out Zero-based numbering for more info.
Change it to
totalincome = total[0] + total[1] + ... + total[29];
Or simply, to make your life much easier, use a loop:
totalincome = 0;
for (int i = 0; i < sizeof(total)/sizeof(total[0]); ++i)
totalincome += total[i];
totalincome = 0;
for (int i = 0; i < sizeof(total)/sizeof(total[0]); ++i)
totalincome += total[i];
For static arrray, this will work. If the array is dynamically allocated or passed as a pointer, you have to keep track of the number of elements.
totalincome = 0;
for (int i = 0; i < numelements; ++i)
totalincome += total[i];
You need to put totalincome out of the loop.