It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
I'm building a table of runners and their times. I need to find the time behind the previous runner in minutes and seconds using modulo. the first 2 records are
Runner: 198
Minutes: 29
Seconds: 05
Runner: 419
Minutes: 30
Seconds: 01
Time behind runner #1?
Here is my code so far:
import java.io.*;
import java.text.*;
public class read3
{
public static void main(String[] args)throws IOException
{
DataInputStream in=new DataInputStream(new FileInputStream("c:\\java\\chapter13\\sheet2\\program2.jdat2"));
int id;
int mins;
int secs;//,num3;
double calc=0,calc2=0;
char chr;
double tcalc=0;
double t1=0,t2=0,t3=0;
NumberFormat money=NumberFormat.getCurrencyInstance();
System.out.println("Runner\tTotal \tTotal \tTime");
System.out.println("Number\tMinutes\tSeconds\tBehind\n");
try
{
while(true)
{
id=in.readInt();
in.readChar();
mins=in.readInt();
in.readChar();
secs=in.readInt();
in.readChar();
System.out.println(id+"\t "+mins+"\t "+secs+"\t"+calc);
}
}
catch(EOFException e)
{
//Hi
}
in.close();
}
}
I just need to know the equation for finding minutes/seconds (in separate variables) using modulo. Can anybody help?
int time1=nbMinutes1*60+nbSeconds1;
int time2=nbMinutes2*60+nbSeconds2;
int differenceInMinutes = (time2-time1)/60;
int differenceinSeconds = (time2-time1)%60;
EDIT:
To apply it to your code, I would do the following :
Integer duration=null;
while(true)
{
id=in.readInt();
in.readChar();
mins=in.readInt();
in.readChar();
secs=in.readInt();
in.readChar();
Integer newDuration=60*mins+secs;
//duration is null for the first one.
if(duration!=null){
System.out.println(id+"\t "+(newDuration-duration)/60+"\t "+secs+"\t"+(newDuration-duration)%60);
}
duration = newDuration;
}
Your problem here is only tangentially associated with knowing how to use modulus. You have one master function doing a mess of things: initializing variables, opening files, iterating through rows, and figuring out display parameters. This is known as procedural programming, and bad procedural programming at that: you want to leverage object oriented programming here.
//note the standards regarding class names: Capitalize Class Names!
//also, pick names that make it clear what you're doing.
public class DisplayTimes
{
DataInputStream in;
//This is not actually the correct way to do this, but it's lightweight enough for this example
List<Integer> runnerIds = new ArrayList<Integer>();
List<Integer> runnerMinutes = new ArrayList<Integer>();
List<Integer> runnerSeconds = new ArrayList<Integer>();
//note that your main method should not throw an exception. Nothing can catch it!!
//also note that this is just an entry point; it probably shouldn't do any work
public static void main(String[] args)
{
DisplayTimes display = new DisplayTimes("c:\\java\\chapter13\\sheet2\\program2.jdat2");
display.readAndDisplay();
}
//constructors are the proper way to initialize object variables
public DisplayTimes(String inputFile) {
//see how much easier this next line is to read?
this.in = new DataInputStream(new FileInputStream(fileName));
}
public void readAndDisplay() {
processData(); //offload processing somewhere else
System.out.println("Runner\tTotal \tTotal \tTime");
System.out.println("Number\tMinutes\tSeconds\tBehind\n");
for (int idx = 0; idx++; idx<runnerIds.size()) {
String output = runnerIds.get(idx)+"\t";
output = output + runnerMinutes.get(idx)+"\t";
output = output + runnerSeconds.get(idx)+"\t";
output = output + calculateDifference(idx)+"\t";
System.out.println(output);
}
}
private void processData() {
boolean moreData = true;
while (moreData) { //offload the work of the loop to another method
moreData = processRunner();
}
}
private boolean processRunner() {
try {
int id=in.readInt();
in.readChar();//how is this file formatted that you need to skip a char?
int mins=in.readInt();
in.readChar();
int secs=in.readInt();
//Here you should really sanity-check your values
//Instead we'll just store them
this.runnerIds.add(id);
this.runnerMinutes(mins);
this.runnerSeconds(secs);
return isFinished();
} catch (EOFException e) {
//Exceptions should NOT be used for program control.
//They should be used when there is bad data.
System.out.println("There was an unexpected termination of the datafile.");
}
}
private boolean isFinished() {
in.mark(1);
if (in.read == -1) {//checks cleanly if we're at the end of the file.
return false;
} else {
in.reset();//moves you back to mark
return true;
}
}
private String calculateDifference(int idx) {
if (idx == 0) { return "\t"; } //First runner is first!
int previousTimeInSeconds = (runnerMinutes.get(idx-1) * 60) + runnerSeconds.get(idx-1);
int nextTimeInSeconds = (runnerMinutes.get(idx) * 60) + runnerSeconds.get(idx);
int delta = (nextTimeInSeconds - previousTimeInSeconds);
return (delta / 60) + "min " + (delta % 60) + "sec \t";
}
}
The main thing you should take away here is that the problem you came here with - calculating the difference between runner a and b - is only a small part of the code you presented. You couldn't present a Short, Self Contained, Correct (Compilable), Example because your code was improperly tangled with other code. By writing clean code you can focus on the one function (calculateDifference()) that you actually needed help with. While I understand you may be beginning and working out of a book (based on what was presented), the most fundamental thing you can learn is how to break down a problem into the smallest pieces possible. Utilize the language to help you with this; don't fight it.
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
I'm new to java, i do study from udemy.
My question is...at the end of learning java i will find out there are n better ways to do the same thing ? (i just want to accelerate the process of learning)
There is my code if some one can give me an example of a better way so i can understand. Thank you !!
public static void main(String[] args) {
toMillesPerHour(50);
toMillesPerHour(90);
toMillesPerHour(100);
toMillesPerHour(130);
toMillesPerHour(-20);
}
public static void toMillesPerHour(double kilomettersPerHour) {
//return round value
if(kilomettersPerHour >= 0) {
kilomettersPerHour = (int) kilomettersPerHour / 1.60934;
int roundKm = (int) kilomettersPerHour;
System.out.println("You travel with speed of: " + roundKm +" Miles");
}else {
System.out.println("Negative value detected");
}
}
You travel with speed of: 31 Miles
You travel with speed of: 55 Miles
You travel with speed of: 62 Miles
You travel with speed of: 80 Miles
Negative value detected
I assume a typical Java developer with some experience would do these things:
change the return type to double (int if you need to round the result);
throw an exception when kilomettersPerHour < 0;
print the results in the main.
For example,
public static double toMillesPerHour(double kilomettersPerHour) {
if (kilomettersPerHour < 0) {
throw new IllegalArgumentException("Negative value detected");
}
return kilomettersPerHour / 1.60934;
}
You could make the change steven35 suggest, but also in your toMilesPerHour method you shouldn't use the parameter variable to store the result of divison. Instead of that you should do something like:
int milesPerHour = (int)kilometersPerHour / 1.60934
This way you don't need to make any additional variables to round your result. Also it's bad practice to modify parameter variables.
You could just define the values in an array and iterate over them. Then every time you add a new value, you don't have to call toMillesPerHour() again.
double[] values = { 50.0, 90.0, 100.0, 130.0, -20.0 };
for (double value : values) {
toMillesPerHour(value);
}
You can use Math.round() for more accurate result.
public static void main(String[] args) {
toMillesPerHour(50);
toMillesPerHour(90);
toMillesPerHour(100);
toMillesPerHour(130);
toMillesPerHour(-20);
}
public static void toMillesPerHour(double kilomettersPerHour) {
//return round value
if(kilomettersPerHour >= 0) {
kilomettersPerHour = kilomettersPerHour / 1.60934;
int roundKm = (int) Math.round( kilomettersPerHour );
System.out.println("You travel with speed of: " + roundKm +" Miles");
}else {
System.out.println("Negative value detected");
}
}
My single biggest issue with this code is that the name toMilesPerHour(50); only tells half the story. 50 what? Don't make me look inside to figure that out.
Not convinced? Ok now I need a method that converts feet per second to miles per hour. What am I supposed to name it that won't cause confusion?
If your method was hanging off a type named KilometersPerHour this name would be fine but as is this name makes the abstraction fail. I have to look inside to know what it means.
You could use varargs. - It allows you to remove alot of code.
You do not need double.
Using parameters as local variables is not so good approach.
Have a look at:
class Printer {
public static void main(String[] args) {
toMillesPerHour(50, 90, 100, 130, -20);
}
public static void toMillesPerHour(int... kilomettersPerHour) {
Arrays.stream(kilomettersPerHour).forEach(Printer::printRound);
//return round value
}
private static void printRound(int kmPerHour) {
String message = (kmPerHour >= 0) ? calculate(kmPerHour) : "Negative value detected";
System.out.println(message);
}
private static String calculate(int kmPerHour) {
int roundKm = (int) (kmPerHour / 1.60934);
return "You travel with speed of: " + roundKm + " Miles";
}
}
So, I've searched around stackoverflow for a bit, but I can't seem to find an answer to this issue.
My current homework for my CS class involves reading from a file of 5000 random numbers and doing various things with the data, like putting it into an array, seeing how many times a number occurs, and finding what the longest increasing sequence is. I've got all that done just fine.
In addition to this, I am (for myself) adding in a method that will allow me to overwrite the file and create 5000 new random numbers to make sure my code works with multiple different test cases.
The method works for the most part, however after I call it it doesn't seem to "activate" until after the rest of the program finishes. If I run it and tell it to change the numbers, I have to run it again to actually see the changed values in the program. Is there a way to fix this?
Current output showing the delay between changing the data:
Not trying to change the data here- control case.
elkshadow5$ ./CompileAndRun.sh
Create a new set of numbers? Y for yes. n
What number are you looking for? 66
66 was found 1 times.
The longest sequence is [606, 3170, 4469, 4801, 5400, 8014]
It is 6 numbers long.
The numbers should change here but they don't.
elkshadow5$ ./CompileAndRun.sh
Create a new set of numbers? Y for yes. y
What number are you looking for? 66
66 was found 1 times.
The longest sequence is [606, 3170, 4469, 4801, 5400, 8014]
It is 6 numbers long.
Now the data shows that it's changed, the run after the data should have been changed.
elkshadow5$ ./CompileAndRun.sh
Create a new set of numbers? Y for yes. n
What number are you looking for? 1
1 was found 3 times.
The longest sequence is [1155, 1501, 4121, 5383, 6000]
It is 5 numbers long.
My code:
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;
public class jeftsdHW2 {
static Scanner input = new Scanner(System.in);
public static void main(String args[]) throws Exception {
jeftsdHW2 random = new jeftsdHW2();
int[] data;
data = new int[5000];
random.readDataFromFile(data);
random.overwriteRandNums();
}
public int countingOccurrences(int find, int[] array) {
int count = 0;
for (int i : array) {
if (i == find) {
count++;
}
}
return count;
}
public int[] longestSequence(int[] array) {
int[] sequence;
return sequence;
}
public void overwriteRandNums() throws Exception {
System.out.print("Create a new set of numbers? Y for yes.\t");
String answer = input.next();
char yesOrNo = answer.charAt(0);
if (yesOrNo == 'Y' || yesOrNo == 'y') {
writeDataToFile();
}
}
public void readDataFromFile(int[] data) throws Exception {
try {
java.io.File infile = new java.io.File("5000RandomNumbers.txt");
Scanner readFile = new Scanner(infile);
for (int i = 0; i < data.length; i++) {
data[i] = readFile.nextInt();
}
readFile.close();
} catch (FileNotFoundException e) {
System.out.println("Please make sure the file \"5000RandomNumbers.txt\" is in the correct directory before trying to run this.");
System.out.println("Thank you.");
System.exit(1);
}
}
public void writeDataToFile() throws Exception {
int j;
StringBuilder theNumbers = new StringBuilder();
try {
PrintWriter writer = new PrintWriter("5000RandomNumbers.txt", "UTF-8");
for (int i = 0; i < 5000; i++) {
if (i > 1 && i % 10 == 0) {
theNumbers.append("\n");
}
j = (int) (9999 * Math.random());
if (j < 1000) {
theNumbers.append(j + "\t\t");
} else {
theNumbers.append(j + "\t");
}
}
writer.print(theNumbers);
writer.flush();
writer.close();
} catch (IOException e) {
System.out.println("error");
}
}
}
It is possible that the file has not been physically written to the disk, using flush is not enough for this, from the java documentation here:
If the intended destination of this stream is an abstraction provided by the underlying operating system, for example a file, then flushing the stream guarantees only that bytes previously written to the stream are passed to the operating system for writing; it does not guarantee that they are actually written to a physical device such as a disk drive.
Because of the HDDs read and write speed, it is advisable to depend as little as possible on HDD access.
Perhaps storing the random number strings to a list when re-running and using that would be a solution. You could even write the list to disk, but this way the implementation does not depend on the time the file is being written.
EDIT
After the OP posted more of its code it became apparent that my original answer is not relatede to the problem. Nonetheless it is sound.
The code OP posted is not enough to see when is he reading the file after writing. It seems he is writing to the file after reading, which of course is what is percieved as an error. Reading after writing should produce a program that does what you want.
Id est, this:
random.readDataFromFile(data);
random.overwriteRandNums();
Will be reflected until the next execution. This:
random.overwriteRandNums();
random.readDataFromFile(data);
Will use the updated file in the current execution.
This question already has answers here:
Can you recommend a Java library for reading (and possibly writing) CSV files? [closed]
(8 answers)
Closed 6 years ago.
So I have received quite a few tips and acquired some resources for learning Java since joining this community. I have now reached week 6 in my class and am working through my third project. I feel like I'm learning a lot but I also have a long road ahead if I want to master Java.
My question this time is how do I get my code to save more than one output to file?
Part of my current project is to do the following:
"When the window is closed, the efficiency values should be computed with >values of n from 0 to 10 and written to a file. Each line of the file > >should contain the value of n, the efficiency of the iterative method for >that value of n and the efficiency of the recursive method. The values >should be separated by commas so the file can be opened with Excel."
I have managed to get the program to write a single entry into the output file. However,I either made an error in the code or missing something critical. Can someone point me to the correct solution? I think I may have to create an array, store the outputs there, then output the array to csv. I have looked at roseindia and viralpatel but those didn't reveal what I was hoping.
Sequence (part I'm screwing up)
package cmisproject3;
public class Sequence {
private static int efficiency = 0;
// method to compute iterative
public static int computeIterative(int n) {
int result = 0;
efficiency = 0;
if (n == 0) {
result = 0;
} else if (n == 1) {
result = 1;
} else {
int secondPrevious = 0;
int previous = 1;
for (int i = 2; i <= n; i++) {
efficiency++;
result = 2 * previous + secondPrevious;
secondPrevious = previous;
previous = result;
}
}
return result;
}
// method to comopute recursive
public static int computeRecursive(int n) {
efficiency = 0;
return computeRecursiveHelper(n);
}
private static int computeRecursiveHelper(int n) {
if (n == 0) {
return 0;
} else if (n == 1) {
efficiency++;
return 1;
} else {
efficiency++;
return 2 * computeIterative(n - 1) + computeIterative(n - 2);
}
}
public static int getEfficiency() {
return efficiency;
}
}
GUI (nailed it?)
package cmisproject3;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import javax.swing.*;
public class CMISProject3 extends JFrame implements ActionListener {
private final int TWICE = 2;
private JLabel jLabel1 = new JLabel(), jLabel2 = new JLabel(), jLabel3 = new JLabel(), jLabel4 = new JLabel(), jLabel5 = new JLabel(), jLabel6 = new JLabel();
private ButtonGroup radioButtons = new ButtonGroup();
private JRadioButton iterativeBtn = new JRadioButton(), recursiveBtn = new JRadioButton();
private JTextField enterN = new JTextField(16), textResult = new JTextField(16), textEfficiency = new JTextField(16);
private JButton computeBtn = new JButton();
private int efficiency;
private Sequence sequence;
private static FileWriter fileWriter;
private File file = new File("output.txt");
// Beginning of the constructor for the GUI
public CMISProject3() throws IOException {
sequence = new Sequence();
setSize(300, 200); // define size of GUI
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new GridLayout(6, 2));
getContentPane().add(jLabel4);
radioButtons.add(iterativeBtn);
iterativeBtn.setSelected(true); // sets Iterative as default GUI selection
iterativeBtn.setText("Iterative");
getContentPane().add(iterativeBtn);
getContentPane().add(jLabel5);
radioButtons.add(recursiveBtn);
recursiveBtn.setText("Recursive");
getContentPane().add(recursiveBtn);
jLabel1.setText("Enter n: ");
getContentPane().add(jLabel1);
getContentPane().add(enterN);
getContentPane().add(jLabel6);
computeBtn.setText("Compute");
computeBtn.addActionListener(this);
getContentPane().add(computeBtn);
jLabel2.setText("Result: ");
getContentPane().add(jLabel2);
getContentPane().add(textResult);
textResult.setEditable(false);
jLabel3.setText("Efficiency: ");
getContentPane().add(jLabel3);
getContentPane().add(textEfficiency);
textEfficiency.setEditable(false);
pack();
}
public void actionPerformed(ActionEvent event) {
int result;
efficiency = 0;
try {
fileWriter = new FileWriter(file);
} catch (IOException e1) {
e1.printStackTrace();
}
if (iterativeBtn.isSelected()) {
result = sequence.computeIterative(Integer.parseInt(enterN.getText()));
} else {
result = sequence.computeRecursive(Integer.parseInt(enterN.getText()));
}
try {
System.out.println(result);
fileWriter.write(result + ", " + sequence.getEfficiency());
} catch (IOException e) {
e.printStackTrace();
}
textResult.setText(Integer.toString(result));
textEfficiency.setText(Integer.toString(sequence.getEfficiency()));
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
CMISProject3 CMISProject3 = new CMISProject3();
CMISProject3.setVisible(true);
}
}
For those interested, here are the parameters I'm working within.
Instructions
You are reopening the file each time an action was performed without telling FileWriter to append instead of overwrite.
See:
https://docs.oracle.com/javase/7/docs/api/java/io/FileWriter.html#FileWriter(java.io.File,%20boolean)
I think you have a good start on your project. However, I see other problems apart from your question.
First I'll address your question then move on to other items. I assume when you say:
write a single entry into the output file
that you're saying you are able to write a single line to the file. So that would mean your question is: How can I write multiple lines to a file?
In that case you have at least two options. One is to setup your FileWriter to append rather than the default behavior of overwriting the existing file content.
Another option would be to avoid closing the FileWriter until you're finished writing. You could, for example, do this by moving the construction of your fileWriter to the constructor of your GUI and moving the call to the close method into an event handler that fires when the GUI closes.
Whatever you chose to do, you need to remember to write the newline character at the end of each line or else your file will be one very long line. So, modifying what you have now it would look like this:
fileWriter.write(result + ", " + sequence.getEfficiency()+"\n");
Other Issues:
Your Sequence.computeRecursiveHelper method is not recursive. A recursive method calls itself, yours does not do this.
I don't think you're following the instructions correctly. Perhaps you're just not finished yet and you intend to modify your code. If that is the case you can ignore what I'm about to point out. The instructions state:
When the window is closed, the efficiency values should be computed with values of n from 0 to 10 and written to a file.
You are currently writing to the file every time the user clicks the "Compute" button rather than doing the above. Also, you're not writing the correct data - you're writing the value you got based on the user's input not values obtained using n from 0 to 10.
This is my first UVa submission so I had a few problems in the way. The biggest hurdle that took my time so far was probably getting all the formats correctly (I know, shouldn't have been too hard but I kept getting runtime error without knowing what that actually meant in this context). I did finally get past that runtime error, but I still get "Wrong answer."
Listed below are the things I've done for this problem. I've been working on this for the last few hours, and I honestly thought about just dropping it altogether, but this will bother me so much, so this is my last hope.
Things I've done:
considered int overflow so changed to long at applicable places
got the whole list (1-1000000) in the beginning through memorization for computation time
submitted to uDebug. Critical input and Random input both show matching output.
submitted to to UVa online judge and got "Wrong Answer" with 0.13~0.15 runtime.
Things I'm not too sure about:
I think I read that UVa doesn't want its classes to be public. So I left mine as class Main instead of the usual public class Main. Someone from another place mentioned that it should be the latter. Not sure which one UVa online judge likes.
input. I used BufferedReader(new InputStreaReader (System.in)) for this. Also not sure if UVa online judge likes this.
I thought my algorithm was correct but because of "Wrong answer," I'm not so sure. If my code is hard to read, I'll try to describe what I did after the code.
Here is my code:
class Main {
public static int mainMethod(long i, int c, List<Integer> l) {
if (i==1)
return ++c;
else if (i%2==0) {
if (i<1000000&&l.get((int)i)!=null)
return l.get((int)i)+c;
else {
c++;
return mainMethod(i/2, c, l);
}
}
else {
if (i<1000000&&l.get((int)i)!=null)
return l.get((int)i)+c;
else {
c++;
return mainMethod(i*3+1, c, l);
}
}
}
public static int countMax(int x, int y, List<Integer> l) {
int max=0;
if (x>y) {
int temp = x;
x= y;
y = temp;
}
for (int i=x; i<=y; i++) {
if (l.get(i)>max)
max = l.get(i);
}
return max;
}
public static void main(String[] args) {
List<Integer> fixed = Arrays.asList(new Integer[1000000]);
for (long i=1; i<1000000; i++) {
fixed.set((int)i, mainMethod(i,0,fixed));
}
String s;
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while ((s = br.readLine())!=null) {
int x = -1;
int y = -1;
for (String split : s.split("\\s+")) {
if (!split.equals("\\s+") && x==-1) {
x = Integer.parseInt(split);
} else if (!split.equals("\\s+") && x!=-1) {
y = Integer.parseInt(split);
}
}
if (x!=-1&&y!=-1)
System.out.println(Integer.toString(x) + " " + Integer.toString(y) + " " + Integer.toString(countMax(x,y,fixed)));
}
} catch (IOException e) {
} catch (NumberFormatException e) {
}
}
}
I apologize for generic names for methods and variables. mainMethod deals with memorization and creating the initial list. countMax deals with the input from the problem (15 20) and finding the max length using the list. The for loop within the main method deals with potential empty lines and too many spaces.
So my (if not so obvious) question is, what is wrong with my code? Again, this worked perfectly fine on uDebug's Random Input and Critical Input. For some reason, however, UVa online judge says that it's wrong. I'm just clueless as to where it is. I'm a student so I'm still learning. Thank you!
Haven't spotted your error yet, but a few things that may make it easier to spot.
First off:
int goes to 2^31, so declaring i in mainMethod to be long is unnecessary. It also states in the problem specification that no operation will overflow an int, doesn't it? Getting rid of the extraneous longs (and (int) casts) would make it easier to comprehend.
Second:
It's probably clearer to make your recursive call with c + 1 than ++c or doing c++ before it. Those have side effects, and it makes it harder to follow what you're doing (because if you're incrementing c, there must be a reason, right?) What you're writing is technically correct, but it's unidiomatic enough that it distracts.
Third:
So, am I missing something, or are you never actually setting any of the values in the List in your memoization function? If I'm not blind (which is a possibility) that would certainly keep it from passing as-is. Wait, no, definitely blind - you're doing it in the loop that calls it. With this sort of function, I'd expect it to mutate the List in the function. When you call it for i=1, you're computing i=4 (3 * 1 + 1) - you may as well save it.
I'm new to OO programing and having a bit of trouble with the design of my program to use the concepts. I have done the tutorials but am still having problem.
I have a recursion that takes a value of items(could be anything in this example, stocks) and figures out what number of them are needed to equal a specific value(in this code 100). This part works but I want to know if a stock's weighting exceeds a threshold. Originally I approached this problem with a method that did a for loop and calculated the entire list of values but this is super inefficient because its doing it on every loop of the recursion. I thought this would be a good time to try to learn classes because I could use a class to maintain state information and just increment the value on each loop and it'll let me know when the threshold is hit.
I think I have the code but I don't fully understand how to design this problem with classes. So far it runs the loop each step of the recursion because I'm initially the class there. Is there a better way to design this? My end goal is to be notified when a weighting is exceeded(which I can somewhat already do) but I want to do in way that uses the least bit of resources(avoiding inefficient/unnecessary for loops)
Code(Here's the entire code I have been using to learn but the problem is with the Counter class and its location within the findVariables method):
import java.util.Arrays;
public class LearningClassCounting {
public static int[] stock_price = new int[]{ 20,5,20};
public static int target = 100;
public static void main(String[] args) {
// takes items from the first list
findVariables(stock_price, 100, new int[] {0,0,0}, 0, 0);
}
public static void findVariables(int[] constants, int sum,
int[] variables, int n, int result) {
Counter Checker = new Counter(stock_price, variables);
if (n == constants.length) {
if (result == sum) {
System.out.println(Arrays.toString(variables));
}
} else if (result <= sum){ //keep going
for (int i = 0; i <= 100; i++) {
variables[n] = i;
Checker.check_total_percent(n, i);
findVariables(constants, sum, variables, n+1, result+constants[n]*i);
}
}
}
}
class Counter {
private int[] stock_price;
private int[] variables;
private int value_so_far;
public Counter(int[] stock_price, int[] variables) {
this.stock_price = stock_price;
this.variables = variables;
for (int location = 0; location < variables.length; location++) {
//System.out.println(variables[location] + " * " + stock_price[location] + " = " + (variables[location] * stock_price[location]) );
value_so_far = value_so_far + (variables[location] * stock_price[location]);
}
//System.out.println("Total value so far is " + value_so_far);
//System.out.println("************");
}
public void check_total_percent(int current_location, int percent) {
// Check to see if weight exceeds threshold
//System.out.println("we are at " + current_location + " and " + percent + " and " + Arrays.toString(variables));
//System.out.println("value is " + stock_price[current_location] * percent);
//formula I think I need to use is:
if (percent == 0) {
return;
}
int current_value = (stock_price[current_location] * percent);
int overall_percent = current_value/(value_so_far + current_value);
if (overall_percent > 50 ) {
System.out.println("item " + current_location + " is over 50%" );
}
}
}
What you're describing sounds like a variant of the famous knapsack problem. There are many approaches to these problems, which are inherently difficult to calculate.
Inherently, one may need to check "all the combinations". The so-called optimization comes from backtracking when a certain selection subset is already too large (e.g., if 10 given stocks are over my sum, no need to explore other combinations). In addition, one can cache certain subsets (e.g., if I know that X Y and Z amount to some value V, I can reuse that value). You'll see a lot of discussion of how to approach these sort of problems and how to design solutions.
That being said, my view is that while algorithmic problems of this sort may be important for learning how to program and structure code and data structures, they're generally a very poor choice for learning object-oriented design and modelling.