double for loop through java array with with an exception - java

I am trying to loop through an array twice, once to create an array of Objects, and then during the creation of the array, check to make sure the address does not exist already in an another array. This is for a Java II class. I've overridden the default equals function to be a comparative one, checking the streetAddress field to see if they match.
The issue I'm trying to avoid is, that first, I create a NewspaperSubscriber object, then I check to make sure it doesn't already exist, however it will always exist if it's already been created! I'm trying to find a way in my second for loop (incrementing on y) to skip whatever element i'm currently processing in it's parent loop (incrementing on x).
Working on it for a while now, having a hard time with my exception. I don't want to modify my NeswpaperSubscriber class, as it needs to compare NeswpaperSubscriber.String to NewspaperSubscriber.String, not NewspaperSubscriber.String to String. Thoughts?
import javax.swing.*;
import java.util.Scanner;
public class Subscribers {
static int x, y;
public static Scanner input = new Scanner(System.in);
public static void main(String[] args) {
NewspaperSubscriber[] subscribers= new NewspaperSubscriber[5];
for (x = 0; x < subscribers.length; ++x) {
System.out.println("x = " + x);
String userEntry;
int subscriberType;
String address;
userEntry = JOptionPane.showInputDialog(null, "Please select the type of \n" +
"subscribers you want to enter: \n" +
"\t1 - Seven Day\n" +
"\t2 - Weekday\n" +
"\t3 - Weekend");
subscriberType = Integer.parseInt(userEntry);
if (subscriberType == 1) {
address = addressEntry();
subscribers[x] = new SevenDaySubsriber(address);
checkAddress(subscribers, subscribers[x]);
} else if (subscriberType == 2) {
subscribers[x] = new WeekdaySubscriber(addressEntry());
} else {
subscribers[x] = new WeekendSubscriber(addressEntry());
}
}
StringBuffer outString = new StringBuffer();
for (x = 0; x < subscribers.length; ++x) {
outString.append("\n#" + (x + 1) + " ");
outString.append(subscribers[x].toString());
}
JOptionPane.showMessageDialog(null, " Our available subscribers include: \n" + outString);
}
public static String addressEntry() {
String enteredAddress = JOptionPane.showInputDialog(null, "Please enter address");
System.out.println(enteredAddress);
return enteredAddress;
}
public static void checkAddress(NewspaperSubscriber[] subscribers, NewspaperSubscriber newSub) {
for (y = 0; y < subscribers.length && y !=x; ++y) {
System.out.println("x = " + x);
System.out.println();
System.out.println("y = " + y);
System.out.println();
if (subscribers[y].equals(newSub)) {
JOptionPane.showMessageDialog(null, "That address already exists!");
} else {
}
}
}
}
//From base class Newspaper subscriber
public boolean equals(NewspaperSubscriber otherSubscriber) {
boolean result;
if (streetAddress == otherSubscriber.streetAddress)
result = true;
else result = false;
return result;
}
my results!
x = 0
123
x = 1
123
x = 2
123
x = 3
Exception in thread "main" java.lang.NumberFormatException: null
at java.lang.Integer.parseInt(Integer.java:542)
at java.lang.Integer.parseInt(Integer.java:615)
at Subscribers.main(Subscribers.java:25)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Process finished with exit code 1

So basically I recognize the following questions:
Question 1
I'm trying to find a way in my second for loop (incrementing on y) to skip whatever element i'm currently processing in it's parent loop (incrementing on x).
Just don't insert the new element before doing the check. Hence, you want to swap these two lines:
subscribers[x] = new SevenDaySubsriber(address);
checkAddress(subscribers, subscribers[x]);
To fulfill the odd requirements of your instructor you could pass the index where you insert the new subscriber to your checkAddress method and just skip it. However this restriction itself is very strange (to not call it bad design).
public static void checkAddress(NewspaperSubscriber[] subscribers, NewspaperSubscriber newSub, int skipIndex) {
for (int y = 0; y < subscribers.length; ++y) {
if (y != skipIndex && subscribers[y].equals(newSub)) {
JOptionPane.showMessageDialog(null, "That address already exists!");
}
}
Question 2
Working on it for a while now, having a hard time with my exception.
The Exception occurs at the line
subscriberType = Integer.parseInt(userEntry);
You closed (cancelled) the popup window which makes JOptionPane.showInputDialog(...) return null. This is obviously not a valid Integer, which is why you get the mentioned Exception.
Note
In your method NewspaperSubscriber.equals(...) you should use String.equals(other) rather than ==. For more information see here.

Related

I have some problems with ArrayList (quiz of head first java)

I've just started learning java since last week. I'm using book called 'head first java' and i'm struggling with solving problems about ArrayList. Error says "The method setLocationCells(ArrayList) in the type DotCom is not applicable for the
arguments (int[])" and I haven't found the solution :( help me..!
enter image description here
This looks like a Locate & Conquer type game similar to the game named Battleship with the exception that this game is a single player game played with a single hidden ship in a single horizontal row of columnar characters. Rather simplistic but kind of fun to play I suppose. The hard part is to locate the hidden ship but once you've located it, conquering (sinking) it becomes relatively easy. I'm sure this isn't the games' intent since it is after all named "The Dot Com Game" but the analogy could be possibly helpful.
There are several issues with your code but there are two major ones that just can not be there for the game to work:
Issue #1: The call to the DotCom.setLocationCells() method:
The initial problem is located within the DotComGame class on code line 13 (as the Exception indicates) where the call is made to the DotCom.setLocationCells() method. As already mentioned in comments the wrong parameter type is passed to this method. You can not pass an int[] Array to the setLocationCell() method when this method contains a parameter signature that stipulates it requires an ArrayList object. The best solution in my opinion would be to satisfy the setLocationCells() method parameter requirement...supply an ArrayList to this method.
The reason I say this is because all methods within the DotCom class work with an established ArrayList and one of the tasks of one of these methods (the checkYourself() method) actually removes elements from the ArrayList which is easy to do from a collection but very cumbersome to do the same from an Array.
To fix this problem you will need to change the data type for the locations variable located within the DotComGame class. Instead of using:
int[] locations = {randomNum, randomNum + 1, randomNum + 2};
you should have:
ArrayList<Integer> locations = new ArrayList<>(
Arrays.asList(random, randomNum + 1, randomNum + 2));
or you could do it this way:
ArrayList<Integer> locations = new ArrayList<>();
locations.add(randomNum);
locations.add(randomNum + 1);
locations.add(randomNum + 2);
There are other ways but these will do for now. Now, when the call to the setLocationCells() method is made you ahouldn't get an exception this issue should now be resolved.
Issue #2: The call to the DotCom.checkYourself() method:
Again, this particular issue is located within the DotComGame class on code line 18 where the call is made to the DotCom.checkYourself() method. Yet another parameter data type mismatch. You are trying to pass a variable of type String (named guess) to this method whereas its signature stipulates that it requires an integer (int) value. That again is a no go.
To fix this problem you will need to convert the string numerical value held by the guess variable to an Integer (int) value. So instead of having this:
while(isAlive) {
String guess = helper.getUserInput("Enter a Number: ");
String result = theDotCom.checkYourself(guess);
// ... The rest of your while loop code ...
}
you should have something like:
while(isAlive) {
String guess = helper.getUserInput("Enter a Number: ");
/* Validate. Ensure guess holds a string representation
of a Integer numerical value. */
if (!guess.matches("\\d+")) {
System.err.println("Invalid Value (" + guess
+ ") Supplied! Try again...");
continue;
}
int guessNum = Integer.parseInt(guess);
String result = theDotCom.checkYourself(guessNum);
numOfGuesses++;
if (result.equals("kill")) {
isAlive = false;
System.out.println(numOfGuesses + " guesses!");
}
else if (result.equals("hit")) {
// Do Something If You Like
System.out.println("HIT!");
}
else {
System.out.println("Missed!");
}
}
Below is a game named Simple Battleship which I based off of your code images (please don't use images for code anymore - I hate using online OCR's ;)
BattleshipGame.java - The application start class:
import java.awt.Toolkit;
public class BattleshipGame {
public static int gameLineLength = 10;
public static void main(String[] args) {
GameHelper helper = new GameHelper();
Battleship theDotCom = new Battleship();
int score = 0; // For keeping an overall score
// Display About the game...
System.out.println("Simple Battleship Game");
System.out.println("======================");
System.out.println("In this game you will be displayed a line of dashes.");
System.out.println("Each dash has the potential to hide a section of a");
System.out.println("hidden Battleship. The size of this ship is randomly");
System.out.println("chosen by the game engine and can be from 1 to 5 sections");
System.out.println("(characters) in length. The score for each battle is based");
System.out.println("on the length of the game line that will be displayed to");
System.out.println("you (default is a minimum of 10 charaters). You now have");
System.out.println("the option to supply the game line length you want to play");
System.out.println("with. If you want to use the default then just hit ENTER:");
System.out.println();
// Get the desire game line length
String length = helper.getUserInput("Desired Game Line Length: --> ", "Integer", true, 10, 10000);
if (!length.isEmpty()) {
gameLineLength = Integer.parseInt(length);
}
System.out.println();
// Loop to allow for continuous play...
boolean alwaysReplay = true;
while (alwaysReplay) {
int numOfGuesses = 0;
/* Create a random ship size to hide within the line.
It could be a size from 1 to 5 characters in length. */
int shipSize = new java.util.Random().nextInt((5 - 1) + 1) + 1;
int randomNum = (int) (Math.random() * (gameLineLength - (shipSize - 1)));
int[] locations = new int[shipSize];
for (int i = 0; i < locations.length; i++) {
locations[i] = randomNum + i;
}
System.out.println("Destroy the " + shipSize + " character ship hidden in the");
System.out.println("displayed line below:");
System.out.println();
String gameLine = String.join("", java.util.Collections.nCopies(gameLineLength, "-"));
theDotCom.setLocationCells(locations);
// Play current round...
boolean isAlive = true;
while (isAlive == true) {
System.out.println(gameLine);
String guess = helper.getUserInput("Enter a number from 1 to " + gameLineLength
+ " (0 to quit): --> ", "Integer", 1, gameLineLength);
int idx = Integer.parseInt(guess);
if (idx == 0) {
System.out.println("Quiting with an overall score of: " + score + " ... Bye-Bye");
alwaysReplay = false;
break;
}
idx = idx - 1;
String result = theDotCom.checkYourself(idx);
numOfGuesses++;
System.out.println(result);
if (result.equalsIgnoreCase("kill")) {
Toolkit.getDefaultToolkit().beep();
isAlive = false;
/* Tally the score dependent upon the gameLineLength... */
if (gameLineLength <= 10) { score += 5; }
else if (gameLineLength > 10 && gameLineLength <= 20) { score += 10; }
else if (gameLineLength > 20 && gameLineLength <= 30) { score += 15; }
else if (gameLineLength > 30 && gameLineLength <= 40) { score += 20; }
else { score += 25; }
gameLine = gameLine.substring(0, idx) + "x" + gameLine.substring(idx + 1);
System.out.println(gameLine);
System.out.println(numOfGuesses + " guesses were made to sink the hidden ship.");
System.out.println("Your overall score is: " + (score < 0 ? 0 : score));
}
else if (result.equalsIgnoreCase("hit")) {
gameLine = gameLine.substring(0, idx) + "x" + gameLine.substring(idx + 1);
}
if (result.equalsIgnoreCase("miss")) {
score -= 1;
}
System.out.println();
}
// Play Again? [but only if 'alwaysReplay' holds true]
if (alwaysReplay) {
String res = helper.getAnything("<< Press ENTER to play again >>\n"
+ "<< or enter 'q' to quit >>");
if (res.equalsIgnoreCase("q")) {
System.out.println("Quiting with an overall score of: " + score + " ... Bye-Bye");
break;
}
System.out.println();
}
}
}
}
GameHelper.java - The GameHelper class:
import java.util.Scanner;
public class GameHelper {
private final Scanner in = new Scanner(System.in);
public String getUserInput(String prompt, String responseType, int... minMAX) {
int min = 0, max = 0;
if (minMAX.length == 2) {
min = minMAX[0];
max = minMAX[1];
}
if (minMAX.length > 0 && min < 1 || max < 1) {
throw new IllegalArgumentException("\n\ngetUserInput() Method Error! "
+ "The optional parameters 'min' and or 'max' can not be 0!\n\n");
}
String response = "";
while (response.isEmpty()) {
if (prompt.trim().endsWith("-->")) {
System.out.print(prompt);
}
else {
System.out.println(prompt);
}
response = in.nextLine().trim();
if (responseType.matches("(?i)\\b(int|integer|float|double)\\b")) {
if (!response.matches("-?\\d+(\\.\\d+)?") ||
(responseType.toLowerCase().startsWith("int") && response.contains("."))) {
System.err.println("Invalid Entry (" + response + ")! Try again...");
response = "";
continue;
}
}
// Check entry range value if the entry is to be an Integer
if (responseType.toLowerCase().startsWith("int")) {
int i = Integer.parseInt(response);
if (i != 0 && (i < min || i > max)) {
System.err.println("Invalid Entry (" + response + ")! Try again...");
response = "";
}
}
}
return response;
}
public String getUserInput(String prompt, String responseType, boolean allowNothing, int... minMAX) {
int min = 0, max = 0;
if (minMAX.length == 2) {
min = minMAX[0];
max = minMAX[1];
}
if (minMAX.length > 0 && min < 1 || max < 1) {
throw new IllegalArgumentException("\n\ngetUserInput() Method Error! "
+ "The optional parameters 'min' and or 'max' can not be 0!\n\n");
}
String response = "";
while (response.isEmpty()) {
if (prompt.trim().endsWith("-->")) {
System.out.print(prompt);
}
else {
System.out.println(prompt);
}
response = in.nextLine().trim();
if (response.isEmpty() && allowNothing) {
return "";
}
if (responseType.matches("(?i)\\b(int|integer|float|double)\\b")) {
if (!response.matches("-?\\d+(\\.\\d+)?") ||
(responseType.toLowerCase().startsWith("int") && response.contains("."))) {
System.err.println("Invalid Entry (" + response + ")! Try again...");
response = "";
continue;
}
}
// Check entry range value if the entry is to be an Integer
if (responseType.toLowerCase().startsWith("int")) {
int i = Integer.parseInt(response);
if (i != 0 && (i < min || i > max)) {
System.err.println("Invalid Entry (" + response + ")! Try again...");
response = "";
}
}
}
return response;
}
public String getAnything(String prompt) {
if (prompt.trim().endsWith("-->")) {
System.out.print(prompt);
}
else {
System.out.println(prompt);
}
return in.nextLine().trim();
}
}
Battleship.java - The Battleship class:
import java.util.ArrayList;
public class Battleship {
private ArrayList<Integer> locationCells;
public void setLocationCells(java.util.ArrayList<Integer> loc) {
locationCells = loc;
}
// Overload Method (Java8+)
public void setLocationCells(int[] loc) {
locationCells = java.util.stream.IntStream.of(loc)
.boxed()
.collect(java.util.stream.Collectors
.toCollection(java.util.ArrayList::new));
}
/*
// Overload Method (Before Java8)
public void setLocationCells(int[] loc) {
// Clear the ArrayList in case it was previously loaded.
locationCells.clear();
// Fill the ArrayList with integer elements from the loc int[] Array
for (int i = 0; i < loc.length; i++) {
locationCells.add(loc[i]);
}
}
*/
/**
* Completely removes one supplied Integer value from all elements
* within the supplied Integer Array if it exist.<br><br>
*
* <b>Example Usage:</b><pre>
*
* {#code int[] a = {103, 104, 100, 10023, 10, 140, 2065};
* a = removeFromArray(a, 104);
* System.out.println(Arrays.toString(a);
*
* // Output will be: [103, 100, 10023, 10, 140, 2065]}</pre>
*
* #param srcArray (Integer Array) The Integer Array to remove elemental
* Integers from.<br>
*
* #param intToDelete (int) The Integer to remove from elements within the
* supplied Integer Array.<br>
*
* #return A Integer Array with the desired elemental Integers removed.
*/
public static int[] removeFromArray(int[] srcArray, int intToDelete) {
int[] arr = {};
int cnt = 0;
boolean deleteIt = false;
for (int i = 0; i < srcArray.length; i++) {
if (srcArray[i] != intToDelete) {
arr[cnt] = srcArray[i];
cnt++;
}
}
return arr;
}
public String checkYourself(int userInput) {
String result = "MISS";
int index = locationCells.indexOf(userInput);
if (index >= 0) {
locationCells.remove(index);
if (locationCells.isEmpty()) {
result = "KILL";
}
else {
result = "HIT";
}
}
return result;
}
}

Validating user input in arrays

Hey guys I am doing a project for school and am having a little trouble, I have a variable "reservationNumber" and im attempting to check if the number the user inputs is in the array, if not it returns a string saying the number was not found. It is working fine and displays the correct info when there is a valid input but when an invalid input is detected it gives a null.pointer.exception error. I tried writing it so that if the number is not detected the private method returns -1, then when I call the tickerInformation method, if that the variable 'ticket' returns -1 then it returns "invalid reservation number". This is where is error is being raised and only occurs when I enter an invalid number please help.
public void ticketInformation(String reservationNumber)
{
int ticket = searchArray(reservationNumber);
if (ticket == -1)
{
System.out.println("The reservation number entered was n0t found");
}
else
{
System.out.print("\n" + ticketSale[ticket].toString());
}
}
private int searchArray(String reservationNumber)
{
for (int i = 0; i < ticketSale.length; i++)
{
if (ticketSale[i].getReservationNumber().equals(reservationNumber))
{
return i;
}
}
return -1;
}
ticketSale[i].getReservationNumber().equals(reservationNumber) has an issue. Share the declaration and init for array "ticketSale". If ticketSale array is for abstract data type then why equal is called with String?
You didn't post the whole code but I think that when you enter invalid number as reservation number, it does not assigned to the related object's instance variable. So getReservationNumber() might be returning null.
Add a null check,
private int searchTicketSales(String reservationNumber) {
int reservationNumberIndex = -1;
for (int i = 0; i < ticketSale.length; i++) {
if (null != ticketSale[i].getReservationNumber() && ticketSale[i].getReservationNumber().equals(reservationNumber)) {
reservationNumberIndex = i;
break;
}
}
return reservationNumberIndex;
}
Best Regards,
Rakesh
Add a regex to validate that your input is a valid number "\\d+":
public void ticketInformation(String reservationNumber)
{
String regex = "\\d+";
if(!reservationNumber.matches(regex))
{
System.out.println("The reservation number entered was n0t found");
}
int ticket = searchArray(reservationNumber);
if(ticket == -1)
{
System.out.println("The reservation number entered was n0t found");
}
else
{
System.out.print("\n" + ticketSale[ticket].toString());
}
}
You might want to validate searchArray, particularly if it is not used interdependently from ticketInformation().

Variable returning value of previously entered element in java arraylist

I'm trying create a program that use dialog boxes and stores elements in Object Goals(string, int, int). This is just a home project I've decided to do during Uni holidays.
So far it's working how I planned but there is one bug I can't figure out.
//asks user to input goals and stores them in an array list
public static void setup(){
int n = 0;
int i = 0;
boolean setupFinished = false;
boolean success = false;
List<Goals> setupList = new ArrayList<Goals>();
JOptionPane setupBox = new JOptionPane();
while(!setupFinished){
Goals goal = new Goals();
String str1 = JOptionPane.showInputDialog("A goal you wish to work on?");
if(str1 == null){
System.exit(0);
}
goal.setGoal(str1);
String goalPrefInput = JOptionPane.showInputDialog("What is the initial preference of this goal compare to the others?");
if(goalPrefInput == null){
System.exit(0);
} else if (goalPrefInput.equalsIgnoreCase("")){
n = Integer.parseInt("1");
} else {
while(!success){
try {
n = (Integer.parseInt(goalPrefInput));
success = true;
}
catch (Exception NumberFormatException){
JOptionPane.showMessageDialog(null, "You must enter a valid number");
}
}
}
goal.setGoalPref(n);
System.out.println(goal.getGoalPref());
success = false;
String goalFreqInput = JOptionPane.showInputDialog("What is the frequency rate you wish this preference to increase?");
if(goalFreqInput == null){
System.exit(0);
} else if (goalFreqInput.equalsIgnoreCase("")){
n = Integer.parseInt("1");
} else {
while(!success){
try {
n = (Integer.parseInt(goalFreqInput));
success = true;
}
catch (Exception NumberFormatException){
JOptionPane.showMessageDialog(null, "You must enter a valid number");
}
}
}
goal.setGoalPrefIncrease(n);
System.out.println(goal.getGoalPrefIncrease());
setupList.add(i, goal);
i++;
int f = JOptionPane.showConfirmDialog(null, "Have you finished setup?", "Setup Finished?", YES_NO_OPTION);
if(f == JOptionPane.YES_OPTION){
setupFinished = true;
}
}
System.out.print(setupList.toString());
String s = removeBrackets(setupList.toString());
JOptionPane.showMessageDialog(setupBox, "Here are your goals \n" + s);
}
}
It's not finished but what is happening that I don't understand is that the user will enter the first instance of goal the user will put in -
goal: a, goalPref: 1, goalFreq: 1.
Then the second instance they will put in
goal: b, goalPref: 2, goalFreq: 2.
However for the second instance the goalPref that is suppose to 2 will return 1 whilst goalFreq will return a 2 correctly. If the next instance is
goal: c, goalPref: 3 goalFreq: 3.
Then it will return c, 2, 3 as the previous goalPref was 2.
The thing that confuses me is the code for entering goalPref and goalFreq is identical so why is one working and one isn't?
Here is the Goals class code:
public class Goals {
private String goal;
private int goalPref;
private int goalPrefIncrease;
public String getGoal() {
return goal;
}
public void setGoal(String goal) {
this.goal = goal;
}
public int getGoalPref() {
return goalPref;
}
public void setGoalPref(int goalPref) {
this.goalPref = goalPref;
}
public int getGoalPrefIncrease() {
return goalPrefIncrease;
}
public void setGoalPrefIncrease(int goalPrefIncrease) {
this.goalPrefIncrease = goalPrefIncrease;
}
#Override
public String toString() {
String s = "Goal: " + this.getGoal() + ", Goal Preference: " + this.getGoalPref() + ", Goal Frequency Rate: " + this.getGoalPrefIncrease();
//String s = goal + ", Goal Preference: " + goalPref + ", Goal Frequency Rate: " + goalPrefIncrease;
return s;
}
}
You should have used a debugger to see what is the mistake in your code. The problem here is your success variable which holds a key in determining value of n for your inputs.
Currently at the end of your loop it is true so in next cycle its value is still true and after entering goal pref it is not going in your while(!success) loop to determine value of n so last value of n(which is last value of goal frequency you entered) is assigned to new goal pref.
In order to correct it you need to reset value of success to false at the start of every iteration.
while(!setupFinished){
success = false;
Goals goal = new Goals();
Hope this helps.

Printing randomly fed values from an ArrayList in Java

I am processing elements of an ArrayList in random order, generally by printing them out. I would like to detect when the randomly selected index is 0 or 1 so as to perform special handling for those cases, where the handling for index 0 is partially dependent on whether index 1 has previously been processed. Specifically, nothing is immediately printed when index 1 is processed, but if it is processed then when index 0 is subsequently processed, both the index 1 and the index 0 values are printed. In any event, the loop is exited after ten iterations or after processing index 0, whichever comes first.
I tried to implement this using if statements, but there where obvious flaws with that one. I have searched everywhere for any examples but found none. I have begun to consider using sorting algorithms or threads to hold the first value found then continue looping until it sees the second the print it out. I would appreciate any help possible.
Here is my code:
public static void random_sortType(){
types = new ArrayList<String>();
types.add("Start");
types.add("Starting");
types.add("Load");
types.add("Loading");
types.add("End");
ran = new Random();
int listSize = types.size();
String tempEventType;//the temp variable intended to hold temporary values
for(int i = 0; i < 10; i++){ //the loop goes round the ArrayList 10 times
int index = ran.nextInt(listSize);//this produces the random selection of the elements within the list
if(index == 0){
out.println(types.get(index));
out.println();
break;
}
if(index == 1){
tempEventType = types.get(index);
if(index == 0){
tempEventType = types.get(0) + " " + types.get(1);
out.println(tempEventType);
break;
}
}/*if(index == 0){
tempEventType = types.get(0) + " " + types.get(1);
out.println(tempEventType);
break;
}*/
//out.print("Index is " + index + ": ");
//out.println(types.get(index));
}
}
You need to store the random generated index into a global variable and update it everytime a random number is generated. It should be something like this.
public static void random_sortType(){
types = new ArrayList<String>();
types.add("Start");
types.add("Starting");
types.add("Load");
types.add("Loading");
types.add("End");
` int previousIndex;
ran = new Random();
int listSize = types.size();
String tempEventType;//the temp variable intended to hold temporary values
for(int i = 0; i < 10; i++){ //the loop goes round the ArrayList 10 times
int index = ran.nextInt(listSize);//this produces the random selection of the elements within the list
previous_index =index;
if(index == 0){
out.println(types.get(index));
out.println();
break;
}
if(index == 1){
tempEventType = types.get(index);
if(previousIndex == 0){
temp EventType = types.get(0) + " " + types.get(1);
out.println(tempEventType);
break;
}
According to your description, these are the basic requirements for your application:
Process ArrayList in random order
Processing = printing value at randomly selected index
Make 10 attempts to process items in the list.
Detect when random index is 1 or 0.
if 1
don't process, but flag it was selected.
if 0 && 1 is flagged
process 0 and 1
exit
If these requirements are correct, here is the implementation I came up with:
import java.util.ArrayList;
import java.util.Random;
import static java.lang.System.*;
public class RandomSort {
private static final int MAX_ATTEMPTS = 10;
private static boolean wasOneSelected = false;
public static void main(String[] args) {
ArrayList<String> types = new ArrayList<>(5);
types.add("Start");
types.add("Starting");
types.add("Load");
types.add("Loading");
types.add("End");
random_sortType(types);
}
public static void random_sortType(ArrayList<String> types) {
Random ran = new Random();
int lastIndex = types.size() - 1; // index range is from 0 to 4
for (int i = 0; i < MAX_ATTEMPTS; i++) {
int index = ran.nextInt(lastIndex);
if ( (index == 0) && wasOneSelected) {
process(types.get(index) + " " + types.get(index + 1));
break;
} else if (index == 1) {
wasOneSelected = true;
} else {
process(types.get(index));
}
}
}
public static void process(String str) {
out.println("Processing: " + str);
}
}
The key here is the inclusion of the boolean wasOneSelected initialized to false. Once it is set to true, it will never be false again for the duration of the application. The if-else block handles all branching within the loop, and I favored wrapping the println call into a method called "process" for readability purposes to align it more closely with your description.
Feedback appreciated :)

Using mutual recursion to do a binary comparison of two files; would prefer to use one method, calling itself. How?

I've made a crossword (and similar) puzzle helper, which enables searching a dictionary for matches to a pattern such as pa??ern, pa*, pa??ern*, etc., where ? and * have the same meaning as wildcards in Windows (? matches any letter; * matches any number of letters [including 0]).
I found two text dictionaries online, one with 108,000+ words, the other with 80,000+. I assumed that the smaller would be a subset of the larger. Not even close.
So I wrote a Java program to compare and to print any word that is in one dictionary but not in the other. (Turned out there were 24,000+ words in the smaller than in the larger; 52,000+ in larger but not in smaller. So I now, via another program, have a dictionary with 132,000+ words.)
I used mutual recursion to accomplish this:
-When current words match, continue; nothing to print here.
-When current word from dictionary A is "<" than current word in B, then...
* print and read A until finding word ">=" current word in B.
--If '=', they match; continue without printing.
--If '>', then reverse the process:
* print and read B until finding word ">=" current word in A.
...
This is all there is to the logic. I really like recursion because it's how we think, though it's often very hard to get those thoughts into code.
And some things about the nature of programmatic recursion are very hard.
In particular, I had to use "dual" methods: one for reading A until >= B; one for reading B until >= A.
I tried to make one routine that would call itself in the same way the different routines call each other, as described above in pseudocode.
I'm asking for someone to show me how to use ONE method to call itself to accomplish the goal.
Here's the code that works but is inefficient, as described:
package filecomparison;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Scanner;
public class ShorterBinaryCompare {
static int kta = 0, exa = 0, ktb = 0, exb = 0;
static Scanner sca, scb;
static String reca, recb;
static Path a = Paths.get("C:\\newdic.txt");
static Path b = Paths.get("C:\\WordHelp.dick");
private static int read_a_untilGE_b(){
while(sca.hasNext()){
if(reca.equals(recb)) return 0; // 0 => a = b
if(reca.compareTo(recb) > 0) break; // a > b
System.out.println(reca); exa++; kta++;
reca = sca.next();
}
read_b_untilGE_a();
return 0;
}
private static int read_b_untilGE_a(){
while(scb.hasNext()){
if(recb.equals(reca)) return 0; // a = b
if(recb.compareTo(reca) > 0) break; // b > a
System.out.println("\t\t" + recb); exb++; ktb++;
recb = scb.next();
}
read_a_untilGE_b();
return 0;
}
private static void drain(String msg, Scanner sc){
int k = 0;
System.out.println("\n\nDraining " + msg);
String s;
while(sc.hasNext()){
s = sc.next();
System.out.println(s);
++k;
}
System.out.println("\nExtras at end: " + k);
}
public static void main(String[] args) throws IOException {
System.out.println("Compare:\n" + a + " vs. \n" + b + "\n");
sca = new Scanner(a); scb = new Scanner(b);
while(sca.hasNext() && scb.hasNext()){
reca = sca.next(); kta++;
recb = scb.next(); ktb++;
int compareResult = reca.compareTo(recb);
if( compareResult < 0) read_a_untilGE_b(); // a < b
else if(compareResult > 0) read_b_untilGE_a() ; // a > b
// mutually-recursive read...untils make a = b at this point
}
System.out.println("\n\nRecords in " + a.toString() + ": " + kta);
System.out.println("Extras in " + a.toString() + ": " + exa);
System.out.println("Records in " + b.toString() + ": " + ktb);
System.out.println("Extras in " + b.toString() + ": " + exb);
if(sca.hasNext()){ drain(a.toFile().toString(), sca); }
if(scb.hasNext()){ drain(b.toFile().toString(), scb); }
}
}
Here's the last version I tried of one method calling itself. It worked as long as it was the "left" file with the extra words, but when it changed so that the "right" file had the extras, it didn't take long to get stack overflow. Maybe I'm closer than I thought; but I'm out of gas for the day.
Can you modify the method below, which calls itself, to do what mutual recursion does in the code above?
private static int read_untilGE_(Scanner a, Scanner b){
String sa, sb;
if(b.hasNext())
sb = b.next();
else
return -1;
System.out.println("Extra in " + a.toString());
while(sca.hasNext()){
sa = sca.next();
if(sa.equals(sb)) return 0; // a = b
if(sa.compareTo(sb) > 0) break; // a > b
System.out.println(sa); exb++; ktb++;
}
read_untilGE_(b, a);
return 0;
}
You got off to the right start by passing your two Scanners as parameters to your method, so that you call your method recursively by switching the parameters. Then you erred by using a Scanner (sca) that wasn't one of the parameters.
Thanks to #ajb's quick response and a good night's (... well, a few hours') sleep, I got exactly what I wanted. The fix wasn't quite as simple as changing Scanner sca to a, but it was exactly the problem that I failed to notice.
And I failed to notice it because of sloppy coding. I had too many global variables, especially sca and scb. Had they been local to main, I'd've caught the problem last night.
Here's the method that calls itself. The '--------------------' lines are the changes relative to the error in logic that ajb pointed out.
private static int read_untilGE_(Scanner a, String sa, long ma,
Scanner b, String sb, long mb){
String indent;
boolean shouldPrint;
if (ma == mapa){indent = inda; shouldPrint = showa;}
else {indent = indb; shouldPrint = showb;}
if(shouldPrint) System.out.println(indent + sa); // --------------------
while(a.hasNext()){ // --------------------
sa = a.next(); // --------------------
if(sa.equals(sb)) return 0; // a = b
if(sa.compareTo(sb) > 0) break; // a > b
if(shouldPrint) System.out.println(indent + sa);
}
read_untilGE_(b, sb, mb, a, sa, ma);
return 0;
}
And here's the rest of the program:
package filecomparison;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Scanner;
public class BinaryCompare {
static long mapa, mapb;
static String inda, indb;
static Boolean showa = true, showb = true;
private static void drain(String msg, Scanner sc){
int k = 0;
System.out.println("\n\nDraining " + msg);
String s;
while(sc.hasNext()){
s = sc.next();
System.out.println(s);
++k;
}
System.out.println("\nExtras at end: " + k);
}
public static void main(String[] args) throws IOException {
Scanner sca, scb;
String reca, recb;
Path a = Paths.get("C:\\newdic.txt");
Path b = Paths.get("C:\\WordHelp.dick");
sca = new Scanner(a); scb = new Scanner(b);
mapa = a.hashCode( ); mapb = b.hashCode();
inda = ""; indb = "\t\t\t";
System.out.println("Extra words in:\n" + inda + " " + a + "\n" + indb + b );
while(sca.hasNext() && scb.hasNext()){
reca = sca.next();
recb = scb.next();
int compareResult = reca.compareTo(recb);
if( compareResult < 0) read_untilGE_(sca, reca, mapa, scb, recb, mapb); // a < b
else if(compareResult > 0) read_untilGE_(scb, recb, mapb, sca, reca, mapa); // a > b
// recursion makes a = b at this point
}
if(sca.hasNext())drain(a.toFile().toString(), sca);
if(scb.hasNext())drain(b.toFile().toString(), scb);
sca.close(); scb.close();
} // end main
}

Categories

Resources