NewToJava
NewToJava

Reputation: 59

Java - Substring Logic

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.

  1. Read a word.
  2. Repeat the loop word.length() times
  3. Pick a random position i in the word, but not the last position.
  4. Pick a random position j > i in the word.
  5. Swap the letters at positions j and i.
  6. Print the word.
  7. Then replace the string with: 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

Answers (6)

Jose Gallo
Jose Gallo

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

NewToJava
NewToJava

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

Java Devil
Java Devil

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

Josh
Josh

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

  1. i >= 0, and
  2. 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

Sage
Sage

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.
  1. Debug your code with a debugger step by step thoroughly to find the BUG.
  2. use Random class which has a nice function random.nextInt(n) to return a random integer between 0 (inclusive) and the specified value (exclusive).

Upvotes: 1

RobisonSantos
RobisonSantos

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

Related Questions