Reputation: 59
I have been trying different things for a while now and I can't figure out why my logic is wrong. It isn't making sense.
I am trying to make a program based on the following pseudocode.
Translate the following pseudocode for randomly permuting the characters in a string into a Java program.
first + word.charAt(j) + middle + word.charAt(i) + last
This is what I have so far:
package assignment4;
import java.util.Scanner;
public class P4Point7 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("Please enter a word: ");
String word = in.next();
in.close();
int wordLength = word.length(); // Gets the word.Length
int x = 1; // Primes the loop
while (x <= wordLength) {
int i = (int) ((Math.random() * wordLength) - 1); // Gets a random letter i that is not the last letter
int j = (int) (Math.random() * (wordLength - i)) + i; // Gets a random letter j after i
String first = word.substring(0, i); // Gets first part of word
String middle = word.substring(i + 1, j); // Gets middle part of word
String last = word.substring(j + 1, wordLength); // Gets last part of word
x++; // Increments the loop
String status = first + word.charAt(j) + middle + word.charAt(i) + last; // Swaps i and j in the word
System.out.println(status);
}
}
}
The problem I am having is
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.substring(Unknown Source)
at assignment4.P4Point7.main(P4Point7.java:21)
I am testing the program with the word "Waffle".
Upvotes: 1
Views: 2435
Reputation: 134
It worked for me with this code:
import java.util.Random;
public class Word
{
private Random generator = new Random();
public Word()
{
generator = new Random();
final long SEED = 42;
generator.setSeed(SEED);
}
public String scramble(String word)
{
int lenWord = word.length();
for (int l = 0; l < lenWord; l++)
{
int i = generator.nextInt(lenWord - 1);
int j = i + 1 + generator.nextInt(lenWord - i - 1);
String letterI = word.substring(i, i + 1);
String letterJ = word.substring(j, j + 1);
String FIRST = word.substring(0, i);
String MIDDLE = word.substring(i + 1, j);;
String LAST = word.substring(j + 1, lenWord);
word = FIRST + letterJ + MIDDLE + letterI + LAST;
}
return word;
}
}
Upvotes: 0
Reputation: 59
This was the solution.
import java.util.Scanner;
public class PermuteCharacters
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
System.out.println("Enter a word to permute: ");
String word = in.next();
for (int n = 0; n < word.length(); n++)
{
/**
The -1 here guarantees that later we won't pick a j that goes off
the end of the string. This is important since since the
pseudocode tells us to pick a j > i
*/
int i = (int) (Math.random() * word.length() - 1);
int j = (int) (Math.random() * (word.length() - i - 1)) + i + 1;
String first = word.substring(0, i);
String middle = word.substring(i + 1, j);
String last = word.substring(j + 1);
word = first + word.charAt(j) + middle + word.charAt(i) + last;
}
System.out.println("Your permuted word is: " + word);
}
}
Upvotes: 0
Reputation: 10959
A Couple of suggestions:
Using a Random
Object to generate your random index may simplify the index generation. Math.random()
returns a double between 0.0 and 1.0. Multiplying this by wordlength is not guaranteed to return a random number in the range 0 to wordlength - 1;
Random indexGen = new Random();
int i = indexGen.nextInt(wordlength -1);
int j = indexGen.nextInt(wordlength -1 - i) + i;
Also the way I read the pseudocode is that you want to just swap the character at i with the character at j so you could do this
char[] charArray = yourWord.toCharArray()
char temp = charArray[i];
charArray[i] = charArray[j];
charArray[j] = temp;
String finalWord = new String(charArray);
Edit using substring
Firstly fix your logic so that your index is always correct and ensure that 0 <= i < j <= wordlength
.
Put that into an if statement then you will know if indices are wrong
if( 0 <= i && i < j && j <=wordlength)
{
String first = word.substring(0, i);
String middle = word.substring(i+1, j);
String last = word.substring(j+1, wordLength);
//... etc
}
else
System.out.println("There was an indexing error: i = " + i + ", j = " + j);
Edit for index
int i = (int) ((Math.random() * wordLength) - 1)
if ( i < 0)
i = 0;
Then same for j but checking j > i
. Another alternative would be to use Math.abs()
like so
int i = Math.abs((int) ((Math.random() * wordLength) - 1))
Upvotes: 1
Reputation: 1553
Like Sage and Java Devil said above, lines 18-19 are causing your problem, but since you're using Math.random()
, it's going to be difficult to reproduce your problem in a debugger - you're creating something that's by nature indeterministic. Since you're looking for random, though, the key is to ensure that
i
>= 0, and j
> i
(or i+1
, depending on the exact results you'd like). This exercise seems to be exploring the Math
library, so I'd suggest looking into some of its other methods for ensuring that i
and j
always have acceptable values (say, Math.min()
and Math.max()
).
Upvotes: 0
Reputation: 15418
i = (int) ((Math.random() * wordLength) - 1);
j = (int) (Math.random() * (wordLength - i)) + i; //
In this two line, there are case (int) (Math.random() * (wordLength - i))
will result in 0
and i == j
. If so then, the following line of code:
String middle = word.substring(i+1, j);
// if i==j, then i+1 > j which will result in index exception.
random.nextInt(n)
to return a random integer between 0 (inclusive) and the specified value (exclusive).Upvotes: 1
Reputation: 651
It seems to me that your i and j can be positions outside the string size. Try changing the way you get the random positions.
Give a try to:
Random rand = new Random();
int i = rand.nextInt(wordLength - 1); // This will return you a random position between 0 and wordLength -2
int j = rand.nextInt(wordLength - i) + i; // This should give you a position after or equals i.
Upvotes: 0