patternjavaMajor
Finding words of different lengths given six letters
Viewed 0 times
sixwordsdifferentlengthsfindinggivenletters
Problem
I'm trying to find all the 3, 4, 5, and 6 letter words given 6 letters. I am finding them by comparing every combination of the 6 letters to an
I tested how many six letter words are checked and got 720 which is good because 65432*1=720 which means I am not checking any words twice. I can't make it faster by getting rid of duplicate checks because I have already gotten rid of them all.
Can I still make this faster?
Note that
```
for(int l1 = 0; l1 < 6; l1++){
for(int l2 = 0; l2 < 6; l2++){
if(l2 != l1)
for(int l3 = 0; l3 < 6; l3++){
if(l3 != l1 && l3 != l2){
if(sortedDictionary.contains(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]))
anagram_words.add(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]);
for(int l4 = 0; l4 < 6; l4++){
if(l4 != l1 && l4 != l2 && l4 != l3){
if(sortedDictionary.contains(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]+anagramCharacters[l4]))
anagram_words.add(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]+anagramCharacters[l4]);
for(int l5 = 0; l5 < 6; l5++){
if(l5 != l1 && l5 != l2 && l5 != l3 && l5 != l4){
if(sortedDictionary.contains(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]+anagramCharacters[l4]+anagramCharacters[l5]))
anagram_words.add(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]+anagramCharacters[l4]+anagramCharacters[l5]);
for(int l6 = 0; l6 < 6; l6++){
ArrayList of words called sortedDictionary. I have worked on the code a good bit to get it to this point.I tested how many six letter words are checked and got 720 which is good because 65432*1=720 which means I am not checking any words twice. I can't make it faster by getting rid of duplicate checks because I have already gotten rid of them all.
Can I still make this faster?
Note that
sortedDictionary only contains about 27 hundred words. ```
for(int l1 = 0; l1 < 6; l1++){
for(int l2 = 0; l2 < 6; l2++){
if(l2 != l1)
for(int l3 = 0; l3 < 6; l3++){
if(l3 != l1 && l3 != l2){
if(sortedDictionary.contains(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]))
anagram_words.add(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]);
for(int l4 = 0; l4 < 6; l4++){
if(l4 != l1 && l4 != l2 && l4 != l3){
if(sortedDictionary.contains(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]+anagramCharacters[l4]))
anagram_words.add(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]+anagramCharacters[l4]);
for(int l5 = 0; l5 < 6; l5++){
if(l5 != l1 && l5 != l2 && l5 != l3 && l5 != l4){
if(sortedDictionary.contains(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]+anagramCharacters[l4]+anagramCharacters[l5]))
anagram_words.add(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]+anagramCharacters[l4]+anagramCharacters[l5]);
for(int l6 = 0; l6 < 6; l6++){
Solution
Before I get started I have to say: Thank you for coming here. Mess of Java For Loops is almost an understatement. Now, let's get working, shall we?
In the below answer I assume that
Code duplication
Start by identifying which parts of the code looks similar, and create some methods to reduce code duplication
Code like this is repeated several times:
This can be extracted to a method:
So instead of repeatedly writing
we simply call a method:
Variables with index
Whenever you find yourself using variable names that contains numbered values, such as
If all the
-
This:
would become
-
This:
can become a method
-
The previous call we made to
So now that's done, what remains now?
After doing the above refactoring, here is what's left:
That looks a lot cleaner, but how flexible is this? What if we want to use an 8-letter word, or a 12-letter word? NO, you should NOT continue this pattern and add more for-loops! So what other alternative is there? Recursive methods, my friend!
To do this, we need a couple of helper methods. You mentioned the number 720. It just so happens that 720 equals 6 factorial. So let's create a factorial method.
This is a recursive because it calls itself on some occasions. More precisely, when
```
public static List permutationI(List values, int iteration) {
if (values.size() == 0)
return new ArrayList();
List list = new ArrayList(values.size());
int divisor = fact(values.size() - 1);
int pos = iteration / divisor; // Pick an index depending on the iteration value
list.add(values.remove((int)pos)); // Remove from one list and add to another
list.addAll(permutationI(values, iteration % divisor)); // C
In the below answer I assume that
sortedDictionary and anagram_words is both of type List. I also assume that anagramCharacters is of type char[].Code duplication
Start by identifying which parts of the code looks similar, and create some methods to reduce code duplication
Code like this is repeated several times:
if(sortedDictionary.contains(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]))
anagram_words.add(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]);This can be extracted to a method:
addWord() (Note that the below method is not optimized for what it is doing, it is mainly so that you are able to understand what it does better).private void addWord(char... chars) {
String string = "";
for (char ch : chars) string += ch; // Create a strings of the chars
if (sortedDictionary.contains(string))
anagram_words.add(string);
}So instead of repeatedly writing
if (sortedDictionary.contains(....)) anagram_words.add(...)we simply call a method:
addWord(anagramCharacters[l1], anagramCharacters[l2], anagramCharacters[l3]);Variables with index
Whenever you find yourself using variable names that contains numbered values, such as
l1, l2, l3, l4, STOP and think "Would an array be useful here?". Creating an int[] letters is far more flexible than using the multiple variables l1, l2, l3If all the
l-variables are instead inside the letters array, some things can be simplified further at the moment: -
This:
if(l4 != l1 && l4 != l2 && l4 != l3)would become
if(letters[3] != letters[0] && letters[3] != letters[1] && letters[3] != letters[2])-
This:
if(letters[3] != letters[0] && letters[3] != letters[1] && letters[3] != letters[2])can become a method
private boolean lastLetterDifferent(int index) {
for (int i = 0; i < index; i++) {
if (letters[i] == letters[index]) return false;
}
return true;
}-
The previous call we made to
addWord only needs to contain the number of indexes to check instead of each and every char.private void addWord(int numberOfChars) {
String string = "";
for (int i = 0; i < numberOfChars; i++) string += anagramCharacters[letters[i]]; // Create a strings of the chars
if (sortedDictionary.contains(string))
anagram_words.add(string);
}So now that's done, what remains now?
After doing the above refactoring, here is what's left:
for(letters[0] = 0; letters[0] < 6; letters[0]++){
for(letters[1] = 0; letters[1] < 6; letters[1]++) {
if(lastLetterDifferent(1)) {
for(letters[2] = 0; letters[2] < 6; letters[2]++) {
if(letters[2] != letters[0] && letters[2] != letters[1]) {
addWord(3);
for(letters[3] = 0; letters[3] < 6; letters[3]++) {
if (lastLetterDifferent(3)) {
addWord(4);
for(letters[4] = 0; letters[4] < 6; letters[4]++){
if (lastLetterDifferent(4)) {
addWord(5);
for(letters[5] = 0; letters[5] < 6; letters[5]++){
if (lastLetterDifferent(5)) {
addWord(6);
}
}
}
}
}
}
}
}
}
}
}That looks a lot cleaner, but how flexible is this? What if we want to use an 8-letter word, or a 12-letter word? NO, you should NOT continue this pattern and add more for-loops! So what other alternative is there? Recursive methods, my friend!
To do this, we need a couple of helper methods. You mentioned the number 720. It just so happens that 720 equals 6 factorial. So let's create a factorial method.
public static int fact(int x) {
if (x < 0) throw new IllegalArgumentException("x cannot be negative: " + x);
if (x <= 1) return 1;
return x * fact(x - 1);
}This is a recursive because it calls itself on some occasions. More precisely, when
x >= 2. Recursive methods are fun, so let's create another one!```
public static List permutationI(List values, int iteration) {
if (values.size() == 0)
return new ArrayList();
List list = new ArrayList(values.size());
int divisor = fact(values.size() - 1);
int pos = iteration / divisor; // Pick an index depending on the iteration value
list.add(values.remove((int)pos)); // Remove from one list and add to another
list.addAll(permutationI(values, iteration % divisor)); // C
Code Snippets
if(sortedDictionary.contains(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]))
anagram_words.add(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]);private void addWord(char... chars) {
String string = "";
for (char ch : chars) string += ch; // Create a strings of the chars
if (sortedDictionary.contains(string))
anagram_words.add(string);
}if (sortedDictionary.contains(....)) anagram_words.add(...)addWord(anagramCharacters[l1], anagramCharacters[l2], anagramCharacters[l3]);if(l4 != l1 && l4 != l2 && l4 != l3)Context
StackExchange Code Review Q#36300, answer score: 36
Revisions (0)
No revisions yet.