# Printing stats based on two words and a letter

This is an exercise that asks to:

Write a program that first asks a user to enter two words and a letter. Then print the first word in uppercase letters and the second word in lowercase letters. Print out the number of letters in both words, how many times the inputted letter occurs in both words, and which positions in each word the letter occurs (assuming zero-indexed Strings).

After this, print whether the words are the same or not, and finally print out both words backwards. You can use either a while loop or for loop if needed for this exercise.

And the sample output would be something like:

Key point to remember:

• Case sensitivity is irrelevant e.g. (if SHooT and sHOot are respectively entered, it would still return that they are the same words and both have 2 letter o's, which are also occurring in the same positions.

I was successful in coding the program:

    import java.util.Scanner;                       //Imports the Scanner
public class exercise2 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);    //Creates a new scanner called 'scan'
String word1, word2, comparison1, comparison2;
char letter, letter1, letter2;
int counter1, counter2, lettercounter1, lettercounter2;
lettercounter1 = lettercounter2 = 0;
System.out.print("Enter two words: ");
word1 = scan.nextLine();
word2 = scan.nextLine();
comparison1 = word1.toUpperCase();
comparison2 = word2.toUpperCase();
System.out.print("Enter a letter: ");
letter = scan.next().charAt(0);
letter1 = Character.toUpperCase(letter);
letter2 = Character.toLowerCase(letter);
System.out.print(word1.toUpperCase());
System.out.print(" " + word2.toLowerCase());
counter1 = word1.length();
counter2 = word2.length();
System.out.println("\nThere are " + counter1 + " letters in " + word1);
System.out.println("There are " + counter2 + " letters in " + word2);
for (int x = 0; x < word1.length(); x++) {
if (word1.charAt(x) == letter1) {
lettercounter1++;
}
else if (word1.charAt(x) == letter2) {
lettercounter1++;
}
}
for (int x = 0; x < word2.length(); x++) {
if (word2.charAt(x) == letter1) {
lettercounter2++;
}
else if (word2.charAt(x) == letter2) {
lettercounter2++;
}
}
System.out.println("There are " + lettercounter1 + " " + letter + "'s in " + word1);
System.out.println("There are " + lettercounter2 + " " + letter + "'s in " + word2);
if (lettercounter1 == 1) {
System.out.print(letter + " occurs in position ");
for (int x = 0; x < word1.length(); x++) {
if (word1.charAt(x) == letter1) {
System.out.print(x + 1);
}
else if (word1.charAt(x) == letter2) {
System.out.print(x + 1);
}
}
System.out.println(" in " + word1);
}
else if (lettercounter1 > 1) {
System.out.print(letter + " occurs in positions ");
for (int x = 0; x < word1.length(); x++) {
if (word1.charAt(x) == letter1) {
System.out.print(x + 1 + ",");
}
else if (word1.charAt(x) == letter2) {
System.out.print(x + 1 + ",");
}
}
System.out.println(" in " + word1);
}
if (lettercounter2 == 1) {
System.out.print(letter + " occurs in position ");
for (int x = 0; x < word2.length(); x++) {
if (word2.charAt(x) == letter1) {
System.out.print(x + 1);
}
else if (word2.charAt(x) == letter2) {
System.out.print(x + 1);
}
}
System.out.println(" in " + word2);
}
else if (lettercounter2 > 1) {
System.out.print(letter + " occurs in positions ");
for (int x = 0; x < word2.length(); x++) {
if (word2.charAt(x) == letter1) {
System.out.print(x + 1 + ",");
}
else if (word2.charAt(x) == letter2) {
System.out.print(x + 1 + ",");
}
}
System.out.println(" in " + word2);
}
if (comparison1.equals(comparison2)) {
System.out.println(word1 + " and " + word2 + " are the same words.");
}
else {
System.out.println(word1 + " and " + word2 + " are not the same words.");
}
int y, z;
y = counter1 - 1;
z = counter2 - 1;
while (y >= 0) {
System.out.print(word1.charAt(y));
y--;
}
System.out.print(" ");
while (z >= 0) {
System.out.print(word2.charAt(z));
z--;
}
}
}


The program works flawlessly and my only questions are:

• Would there be any way to further simplify this code? (e.g. making it as short as possible, using other simpler methods, etc.)
• Any indentation mistakes? Any suggestions?

Would there be any way to further simplify this code? (e.g. making it as short as possible, using other simpler methods, etc.)

Anywhere you repeat yourself, you can create a method, and then call that method. Try this for reversing the strings and for finding occurrences.

You have a lot of variables, which makes it harder to reason about your code. Extracting code into methods will limit this. The next helping step is using function returns:

// temporary locals (more variables, bit harder to reason)
counter1 = word1.length();
counter2 = word2.length();
System.out.println("\nThere are " + counter1 + " letters in " + word1);
System.out.println("There are " + counter2 + " letters in " + word2);

// direct (fewer variables)
System.out.println("\nThere are " + word1.length() + " letters in " + word1);
System.out.println("There are " + word2.length() + " letters in " + word2);


I'm not sure how strict the requirements are. Right now, your code gets two words on two different lines, while the example gets two words from the same line. I've used String.split in the suggestion below, but Scanner.next will work as well.

Some comments will help with eyeball scanning. ;-)

Any indentation mistakes? suggestions?

Try to indent with the code blocks (braces) only. Indentation is meaningless in Java, but it's a strong guideline for humans reading your code. It doesn't matter whether you use 3 or 4 or 2 spaces, as long as you're consistent.

Just a minor issue, when there are multiple positions where 'letter' occurs, how would I avoid printing the last comma? (e.g. it prints out "o occurs in positions 4, 6, in School) instead, I want the comma after 6 to be omitted.

The trick is to give special treatment to your first or your last item. If you know that you have at least one element, you can unroll it and then loop over the rest; the examples below make that clearer:

// special first
for ( int i = 0; i < n; i++ ) {
if ( i > 0 ) print(", ");
print(array[i]);
}

// special last
for ( int i = 0; i < n; i++ ) {
print(array[i]);
if ( i < n - 1 ) print(", ");
}

// unroll first from loop
// verify that array.length > 0 or array[0] will throw!
append(array[0]);
for ( int i = 1; i < n; i++ ) { // start at 1
print(", ");
print(array[i]);
}


Below is a possible implementation, based on the suggestions above.

import java.util.*;

public class exercise2 {
/** Reverses the input string */
static String reverse(String input) {
StringBuilder sb = new StringBuilder(input.length());
for ( int i = input.length() - 1; i >= 0; i-- ) {
sb.append( input.charAt(i) );
}
return sb.toString();
}

/** Finds the 1-based positions in haystack that have needle as char */
static int[] occurrences(String haystack, char needle) {
int[] indices = new int[haystack.length()]; // can't have more occurrences than chars
int count = 0;
for ( int i = 0; i < haystack.length(); i++ ) {
if ( haystack.charAt(i) == needle ) {
indices[count++] = i + 1; // zero-based to one-based
}
}
return Arrays.copyOf(indices, count);
}

/** "<letter> occurs in position(s) <occurs>" */
static String formatOccurences(String word, char letter, int[] occurs) {
StringBuilder line = new StringBuilder();
line.append(letter);
if ( occurs.length == 0 ) {
line.append(" does not appear");
} else {
line.append(" occurs in position");
if ( occurs.length > 1 ) line.append('s');
line.append(' ');
line.append(occurs[0]);
for ( int i = 1; i < occurs.length; i++ ) {
line.append(", ").append(occurs[i]);
}
}
line.append(" in ").append(word);
return line.toString();
}

public static void main(String[] args) {
// input
Scanner scan = new Scanner(System.in);
System.out.print("Enter two words: ");
final String[] words = scan.nextLine().split(" ");
System.out.print("Enter a letter: ");
final char letter = scan.nextLine().charAt(0);

// WORD1 _ word2
System.out.print(words[0].toUpperCase() + " " + words[1].toLowerCase());
System.out.println("\nThere are " + words[0].length() + " letters in " + words[0]);
System.out.println("There are " + words[1].length() + " letters in " + words[1]);

// count occurrences of letter in words
int[] occurrences1 = occurrences(words[0].toLowerCase(), Character.toLowerCase(letter));
System.out.println("There are " + occurrences1.length + " " + letter + "'s in " + words[0]);
int[] occurrences2 = occurrences(words[1].toLowerCase(), Character.toLowerCase(letter));
System.out.println("There are " + occurrences2.length + " " + letter + "'s in " + words[1]);

// print occurrences of letter in words
System.out.println( formatOccurences(words[0], letter, occurrences1) );
System.out.println( formatOccurences(words[1], letter, occurrences2) );

// are words equal?
if (words[0].equalsIgnoreCase(words[1])) {
System.out.println(words[0] + " and " + words[1] + " are the same words.");
} else {
System.out.println(words[0] + " and " + words[1] + " are not the same words.");
}

// print words in reverse
System.out.println(reverse(words[0]) + " " + reverse(words[1]));
}
}


Output:

Enter two words: School House
Enter a letter: o
SCHOOL house
There are 6 letters in School
There are 5 letters in House
There are 2 o's in School
There are 1 o's in House
o occurs in positions 4, 5 in School
o occurs in position 2 in House
School and House are not the same words.
loohcS esuoH