Issue iterating through two arraylists - java

EDIT: Thanks so much for all the really quick feedback. Wow. I did just paste it all for you instead of just those two for loops. Thanks.
This may have been totally answered before. I have read SO for the last few years but this is my first post. I have been using the site and others to help solve this so my apologies in advance if this has been answered!
I am iterating through two arraylists. One is derived from user input; the other is a dictionary file converted into an arraylist. I am trying to compare a word in the input with a dictionary word. The input list and the dictionary list are valid and if I simply iterate through them, they contain what they should (so that isn't the issue. I assume my issue is somewhere with how I am handling the iteration. I'm a fairly novice Java programmer so please go easy on me.
Thanks
public String isSub(String x) throws FileNotFoundException, IOException {
//todo handle X
String out = "**********\nFor input \n" + x + "If you're reading this no match was found.\n**********";
String dictionary;
boolean solve = true;
/// Get dictionary
dictMaker newDict = new dictMaker();
dictionary = newDict.arrayMaker();
List<String> myDict = new ArrayList<String>(Arrays.asList(dictionary.split(",")));
List<String> input = new ArrayList<String>(Arrays.asList(x.split(" ")));
List<String> results = new ArrayList<String>();
//results = input;
String currentWord;
String match = "";
String checker = "";
String fail="";
//Everything to break sub needs to happen here.
while (solve) {
for(int n = 0; n < input.size(); n++) { //outside FOR (INPUT)
if(!fail.equals("")) results.add(fail);
checker = input.get(n).trim();
for(int i = 0; i < myDict.size(); i++) { //inside FOR (dictionary)
currentWord = myDict.get(i).trim();
System.out.print(checker + " " + currentWord + "\n");
if(checker.equals(currentWord)) {
match = currentWord;
results.add(currentWord);
fail="";
} //end if
else {
fail = "No match for " + checker;
}
}//end inside FOR (dictionary)
} //END OUTSIDE FOR (input)
solve=false;
} //end while
out = results.toString();
return out;
}
Output results for input "test tester asdasdfasdlfk"
[test, No match for test, tester, No match for tester]

Carl Manaster gave the correct explanation.
Here's an improved version of your code:
for (int n = 0; n < input.size(); n++) { //outside FOR (INPUT)
String checker = input.get(n).trim();
boolean match = false;
for (int i = 0; i < myDict.size(); i++) { //inside FOR (dictionary)
String currentWord = myDict.get(i).trim();
System.out.print(checker + " " + currentWord + "\n");
if (checker.equals(currentWord)) {
match = true;
results.add(currentWord);
break;
} //end if
} //end inside FOR (dictionary)
if (!match) {
results.add("No match for " + checker);
}
} //END OUTSIDE FOR (input)
Also, consider using a HashMap instead of an ArrayList to store the dictionary and trim the words when you store them to avoid doing it in each pass.

It looks as though every word in input gets compared to every word in your dictionary. So for every word that doesn't match, you get a fail (although you only write the last failure in the dictionary to the results). The problem appears to be that you keep looping even after you have found the word. To avoid this, you probably want to add break to the success case:
if (checker.equals(currentWord)) {
match = currentWord;
results.add(currentWord);
fail = "";
break;
} else {
fail = "No match for " + checker;
}

If you are using a dictionary, you should get it with keys not with index. So it should be
if(myDict.containsKey(checker)){
String currentWord =myDict.get(checker);
System.out.print(checker + " " + currentWord + "\n");
match = currentWord;
results.add(currentWord);
fail = "";
}
else {
fail = "No match for " + checker;
}
I think more or less your code should like following.
ArrayList<String> input= new ArrayList<String>();
input.add("ahmet");
input.add("mehmet");
ArrayList<String> results= new ArrayList<String>();
Map<String, String> myDict = new HashMap<String, String>();
myDict.put("key", "ahmet");
myDict.put("key2", "mehmet");
String match="";
String fail="";
for (int n = 0; n < input.size(); n++) { //outside FOR (INPUT)
if (!fail.equals(""))
results.add(fail);
String checker = input.get(n).trim();
for (int i = 0; i < myDict.size(); i++) { //inside FOR (dictionary)
// String currentWord = myDict.get(i).trim();
if(myDict.containsKey(checker)){
String currentWord =myDict.get(checker);
System.out.print(checker + " " + currentWord + "\n");
match = currentWord;
results.add(currentWord);
fail = "";
}
else {
fail = "No match for " + checker;
}
} // end inside FOR (dictionary)
} // end outside FOR (input)
// solve = false; I dont know what is this
//} //end while. no while in my code
return results.toString();

You should place the dictionary to a HashSet and trim while add all words. Next you just need to loop the input list and compare with dict.conatins(inputWord). This saves the possible huge dictionary loop processed for all input words.
Untested brain dump:
HashSet<String> dictionary = readDictionaryFiles(...);
List<String> input = getInput();
for (String inputString : input)
{
if (dictionary.contains(inputString.trim()))
{
result.add(inputString);
}
}
out = result.toString()
....
And a solution similar to the original posting. The unnecessary loop index variables are removed:
for (String checker : input)
{ // outside FOR (INPUT)
fail = "No match for " + checker;
for (String currentWord : myDict)
{ // inside FOR (dictionary)
System.out.print(checker + " " + currentWord + "\n");
if (checker.equals(currentWord))
{
match = currentWord;
results.add(currentWord);
fail = null;
break;
}
} // end inside FOR (dictionary)
if (fail != null)
{
results.add(fail);
}
} // end outside FOR (input)
solve = false;
return results.toString();
The trim should be made while add the elements to the list. Trim the dictionary values each time is overhead. And the inner loop itself too. The complexity of the task can be reduced if the dictionary data structure is changed from List to Set.
Adding the result of "fail" is moved to the end of the outer loop. Otherwise the result of the last input string is not added to the result list.
The following code is terrible:
else {
fail = "No match for " + checker;
}
The checker does not change within the dictionary loop. But the fail string is constructed each time the checker and the dictionary value does not match.

Related

why does my program loop infinitely?

My spell checking program doesn't give any error codes, just spell-checks the same words over and over, infinitely.
Is there a way to stop this infinite loop and put a cap on how many words it checks, for example, to end the code when ten incorrect words have been corrected?
I'm almost certain that the infinite loop is a result of this method here:
public static void SpellChecker() throws IOException {
dictionary = new Hashtable<String, String>();
System.out.println("Searching for spelling errors ... ");
try {
// Read and store the words of the dictionary
BufferedReader dictReader = new BufferedReader(new FileReader("dictionary.txt"));
while (dictReader.ready()) {
String dictInput = dictReader.readLine();
String[] dict = dictInput.split("\\s"); // create an array of
// dictionary words
for (int i = 0; i < dict.length; i++) {
// key and value are identical
dictionary.put(dict[i], dict[i]);
}
}
dictReader.close();
String user_text = "";
// Initializing a spelling suggestion object based on probability
SuggestSpelling suggest = new SuggestSpelling("wordprobabilityDatabase.txt");
// get user input for correction
while (!user_text.equalsIgnoreCase("q")) {
// CleanString is a string full of words to be spell checked
user_text = cleanString;
String[] words = user_text.split(" ");
int error = 0;
for (String word : words) {
suggestWord = true;
String outputWord = checkWord(word);
if (suggestWord) {
System.out.println("Suggestions for " + word +
" are: " + suggest.correct(outputWord) + "\n");
error++;
}
}
if (error == 0 & !user_text.equalsIgnoreCase("q")) {
System.out.println("No mistakes found");
}
}
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
You never ask the user if he/she wants to quit or not, from inside the while loop. So user_text is initialized with cleanString, and never changes inside the loop, hence the infinite loop.

Morse code in java using HashMap

I try to implement Morse code translator in Java, using as little code as possible, but in my program i get an error, cause hashmap is out of border. Is it possible to assign size of map equals to length of string, that i input? But no less than 26 for not just putting out alphabetical characters. Thanks
String a = reader.readLine();
Map<String, String> words = new HashMap<>();
words.put("s", "***"); //only two characters still
words.put("o", "---");
for(int i=0; i<a.length(); i++)
{
String checker = Character.toString(a.charAt(i));
if(checker.equals(words.keySet().toArray()[i]))
{
System.out.print(words.values().toArray()[i]+" ");
}
}
You just need to see if the current letter is contained within the map, if it is then you can grab the corresponding mapping for it within the words hashmap.
String a = reader.nextLine();
Map<String, String> words = new HashMap<>();
words.put("s", "***"); //only two characters still
words.put("o", "---");
String translated = "";
for(int i=0; i<a.length(); i++)
{
String checker = Character.toString(a.charAt(i));
if(words.containsKey(checker))
{
translated += words.get(checker);
}
else{
translated += checker;
}
}
System.out.println("Input: " + a + ", Morse: " + translated);
Output
sos
Input: sos, Morse: ***---***
sor
Input: sor, Morse: ***---r
This will convert all the letters the map knows about, for those it doesn't it will not change.
if(checker.equals(words.keySet().toArray()[i]))
{
System.out.print(words.values().toArray()[i]+" ");
}
Change this to:
if(words.get(checker) != null)
System.out.print(words.get(checker) + " ");

Matching patterns in List of List in java

I have a ArrayList of strings LinkSet which contains the following items
["0,3","0,13","0,28","12,3","13,3","28,12"]
I have another list of list pattern2 with the following containing
[[0,3], [0,13,3], [0,28,12,3]]
I would like to match each element pattern of the list LinkSet in my list pattern2 and replace the element found by the position of the match from LinkSet. As a result, I would like to have a list of list with like :
[[0],[1,4],[2,5,3]]
From this new list of list, 0 is the position of the "0,3" from the original list,1 is the position of 0,13 in the original list and so on.
I tried this:
String pattern2="";
for (int k=0; k<graph.LinkSet.size();k++)
{
String temp=""
for(int m=0;m<pattern.size();m++)
{
temp=pattern.get(m).toString();
if (temp.contains("[["+LinkSet.get(k)+"],"))
{
pattern=pattern+"[["+k+"],";
}
else if (temp.contains("["+LinkSet.get(k)+"],"))
{
pattern=pattern+"["+k+"],";
}
else if (temp.contains(", ["+LinkSet.get(k)))
{
pattern=pattern+", ["+k+",";
}
else if (temp.contains(", ["+LinkSet.get(k)))
{
pattern=pattern+", ["+k+",";
}
}
}
//System.out.println("after"+temp);
System.out.println("pattern"+pattern2);
But it does not give me what I would like to have. It gives me
,[,[[[1,2,3],
it seems to overwrite pattern2 for each loop
Looks like the problem is, that you're working on "pattern" and change it inside the innner-loop instead of storing your results in pattern2... But that doesn't explain your results. Also you're messing around with the brackets unnecessarily. And you need to switch the loops to get the result you want.
How about this:
String result = "";
// Loop over pattern
for (int m = 0; m < pattern.size(); m++) {
String patternResult = "";
String patternToBeMatched = pattern.get(m);
// Loop over source
for (int k=0; k<graph.LinkSet.size(); k++) {
String toAnalyse = graph.LinkSet.get(k);
if (toAnalyse.contains(patternToBeMatched){
patternResult = patternResult + k + ", ";
}
}
// Remove additional ", " if not empty and set brackets
if (patternResult.length() > 0){
patternResult = "[" + patternResult.substring(0, patternResult.length() - 2) + "]";
}
result = result + patternResult;
}
result = "[" + result + "]";

Guessing method (pretty basic java)

I'm using the following code to add a guessed consonant to a string of stars if the guessed consonant is part of the original word. Initially I was keeping wordWithGuess between calls to getCurrentResult. But the result of this was that the new content was added to the end, and wordWithGuess kept getting longer (instead of just replacing the most recently guessed letter).
When running the code below, the output is
After guessing r: *****r******
After guessing s: ************
After guessing t: **tt********
After guessing l: ********ll**
After guessing n: ***********n
My goal is for it to be:
After guessing r: *****r******
After guessing s: *****r******
After guessing t: **tt*r******
After guessing l: **tt*r**ll**
After guessing n: **tt*r**ll*n
Sample code follows:
public class Sample {
String targetWord;
String wordWithGuess = "";
public Sample(String targetWord) {
this.targetWord = targetWord;
}
public void guess(String consonant) {
wordWithGuess = "";
for (int i = 0; i < targetWord.length(); i++) {
if (targetWord.substring(i, i + 1).equals(" ")) {
wordWithGuess += " ";
} else if (targetWord.substring(i, i + 1).equals(consonant)) {
wordWithGuess += consonant;
} else {
wordWithGuess += "*";
}
}
}
public String getCurrentResult() {
return wordWithGuess;
}
public static void main(String args[]) {
String targetWord = "bitterbollen";
Sample sample = new Sample(targetWord);
String[] guesses = { "r", "s", "t", "l", "n" };
for (String guess : guesses) {
sample.guess(guess);
System.out.println("After guessing " + guess + ": "
+ sample.getCurrentResult());
}
}
}
you should store all consonants guessed, and change
word.substring(i, i + 1).equals (consonant)
to something like
word.substring(i, i + 1) exists in the consonant guessed. (it is pusedo-code of course)
Some more hints: have a look in Set (or more precisely, HashSet), or String's contains() or indexOf() method.
Some extra opinions to you:
you are calling word.substring(i, i + 1) without storing the returned string, that's a meaningless call.
Instead calling word.substring(i, i + 1) that many times, you can call it once and use the returned string for multiple comparison.
And, as you are comparing one char each time, you should use char to store the character, and using charAt() to get the character at certain position.
The problem is that you need to keep some information between calls to guess(). This means either storing all values of consonant, or finding a way to merge the old value of wordWithGuess with the new consonant.
The first option means something like
import java.util.Set;
import java.util.HashSet;
class Sample {
// ...
Set<String> guesses = new HashSet<String>();
public void guess(String consonant) {
guesses.add(consonant);
wordWithGuess = "";
for (int i = 0; i < targetWord.length(); i++) {
String cursor = targetWord.substring(i, i + 1);
if (cursor.equals(" ")) {
wordWithGuess += " ";
} else if (guesses.contains(cursor)) {
wordWithGuess += cursor;
} else {
wordWithGuess += "*";
}
}
}
// ...
}
This stores the old guesses as a Set. Instead of just checking for the last guess, guess() now includes any letter that has been guessed.
In fact you could even add a constructor to initialize the set with any characters that you want to include by default. This will let you eliminate the check for a space, as it'll be in the initial set of guesses:
import java.util.Set;
import java.util.HashSet;
class Sample {
// ...
Set<String> guesses;
public Sample() {
this.guesses = new HashSet<String>();
guesses.add(" ");
}
public void guess(String consonant) {
guesses.add(consonant);
wordWithGuess = "";
for (int i = 0; i < targetWord.length(); i++) {
String cursor = targetWord.substring(i, i + 1);
if (guesses.contains(cursor)) {
wordWithGuess += cursor;
} else {
wordWithGuess += "*";
}
}
}
// ...
}
The other option would be to update wordWithGuess to include the new guess. In C it's easy to do this, because strings can be modified just like character arrays (for example, wordWithGuess[i] = consonant. Java guards its strings more closely, but there's no reason why one can't use an array of char to the same effect.
public class Sample {
String targetWord;
char[] currentResult;
public Sample(String targetWord) {
this.targetWord = targetWord;
currentResult = new char[targetWord.length()];
for (int i = 0; i < targetWord.length(); i++) {
if(targetWord.charAt(i) == ' ') {
currentResult[i] = ' ';
} else {
currentResult[i] = '*';
}
}
}
public void guess(String consonant) {
for (int i = 0; i < targetWord.length(); i++) {
String cursor = targetWord.substring(i, i + 1);
if (cursor.equals(consonant)) {
currentResult[i] = consonant.charAt(0);
}
}
}
public String getCurrentResult() {
return new String(currentResult);
}
// ...
}
You'll want to store the result of the previous iteration. Have the code oldWordWithGuess = wordWithGuess at the end of the for loop.
Then, in your loop you'll want the following code:
...
if(oldWordWithGuess[i] != `*`) {
wordWithGuess += oldWordWithGuess[i];
} else if (word.substring(i, i + 1).equals (" ")) {
...
That way it will put any previous guesses in.
I've actually found a different solution where I use a char Array and store every letter in a different element of that array. Am I actually allowed to do this? Does this not require too much resources for what it does?

How to check for equal words in string array in JAVA

This should be quite simple (I think), but I just can't get it right...:|
The task is as follows:
Ask the user for some input. The input must be split in to single words and put into an array. All words should be counted. If equal words exists, they get a "+1" on the output.
Finally I want to print out and hopefully the right amount of counted words in a list. I got the first two columns right, but the word-counter of equal words gave me a headache. If a word is found to be equal, it mustnt appear twice in the generated list! :!
I am a complete JAVA newbie so please be kind on the code-judging. ;)
Here is my code so far:
package MyProjects;
import javax.swing.JOptionPane;
public class MyWordCount {
public static void main(String[] args) {
//User input dialog
String inPut = JOptionPane.showInputDialog("Write som text here");
//Puts it into an array, and split it with " ".
String[] wordList = inPut.split(" ");
//Print to screen
System.out.println("Place:\tWord:\tCount: ");
//Check & init wordCount
int wordCount = 0;
for (int i = 0; i < wordList.length; i++) {
for (int j = 0; j < wordList.length; j++){
//some code here to compare
//something.compareTo(wordList) ?
}
System.out.println(i + "\t" + wordList[i]+ "\t" + wordCount[?] );
}
}
}
You can use Hashmap to do that. A Hashmap stores key-value pairs and each key has to be unique.
So in your case, a key will be a word of the string you have split and value will be it's count.
Once you have split the input into words and put them into a string array, put the first word,as a key, into the Hashmap and 1 as it's value. For each subsequent word, you can use the function containsKey() to match that word with any of the existing keys in the Hashmap. If it returns true, increment the value (count) of that key by one, else put the word and 1 as a new key-value pair into the Hashmap.
So in order to compare two strings, you do:
String stringOne = "Hello";
String stringTwo = "World";
stringOne.compareTo(stringTwo);
//Or you can do
stringTwo.compareTo(stringOne);
You can't compare a String to a String array like in your comment. You would have to take an element in this string array, and compare that (So stringArray[elementNumber]).
For counting how many words there are, if you are determining the number of repeated words, you would want to have an array of integers (So make a new int[]). Each place in the new int[] should correspond to the word in your array of words. This would allow you to count the number of times a word is repeated.
import java.util.ArrayList;
import java.util.regex.PatternSyntaxException;
import javax.swing.JOptionPane;
public class Main {
/**
* #param args
*/
public static void main(String[] args) {
//Print to screen
System.out.println("Place:\tWord:\tCount: ");
//User input dialog
String inPut = JOptionPane.showInputDialog("Write som text here");
//Puts it into an array, and split it with " ".
String[] wordList;
try{
wordList = inPut.split(" ");
}catch(PatternSyntaxException e) {
// catch the buggy!
System.out.println("Ooops.. "+e.getMessage());
return;
}catch(NullPointerException n) {
System.out.println("cancelled! exitting..");
return;
}
ArrayList<String> allWords = new ArrayList<String>();
for(String word : wordList) {
allWords.add(word);
}
// reset unique words counter
int uniqueWordCount = 0;
// Remove all of the words
while(allWords.size() > 0) {
// reset the word counter
int count = 0;
// get the next word
String activeWord = allWords.get(0);
// Remove all instances of this word
while(doesContainThisWord(allWords, activeWord)) {
allWords.remove(activeWord);
count++;
}
// increase the unique word count;
uniqueWordCount++;
// print result.
System.out.println(uniqueWordCount + "\t" + activeWord + "\t" + count );
}
}
/**
* This function returns true if the parameters are not null and the array contains an equal string to newWord.
*/
public static boolean doesContainThisWord(ArrayList<String> wordList, String newWord) {
// Just checking...
if (wordList == null || newWord == null) {
return false;
}
// Loop through the list of words
for (String oldWord : wordList) {
if (oldWord.equals(newWord)) {
// gotcha!
return true;
}
}
return false;
}
}
Here's a solution using a map of WordInfo objects that records locations of the words within the text and uses that as a count. The LinkedHashMap preserves the order of keys from when they are first entered so simply iterating through the keys gives you the "cast in order of appearance"
You can make this case insensitive while preserving the case of the first appearance by storing all keys as lower case but storing the original case in the WordInfo object. Or just convert all words to lower case and leave it at that.
You may also want to think about removing all , / . / " etc from the first text before splitting, but you'll never get that perfect anyway.
import java.util.LinkedHashMap;
import java.util.Map;
import javax.swing.JOptionPane;
public class MyWordCount {
public static void main(String[] args) {
//User input dialog
String inPut = JOptionPane.showInputDialog("Write som text here");
Map<String,WordInfo> wordMap = new LinkedHashMap<String,WordInfo>();
//Puts it into an array, and split it with " ".
String[] wordList = inPut.split(" ");
for (int i = 0; i < wordList.length; i++) {
String word = wordList[i];
WordInfo wi = wordMap.get(word);
if (wi == null) {
wi = new WordInfo();
}
wi.addPlace(i+1);
wordMap.put(word,wi);
}
//Print to screen
System.out.println("Place:\tWord:\tCount: ");
for (String word : wordMap.keySet()) {
WordInfo wi = wordMap.get(word);
System.out.println(wi.places() + "\t" + word + "\t" + wi.count());
}
}
}
And the WordInfo class:
import java.util.ArrayList;
import java.util.List;
public class WordInfo {
private List<Integer> places;
public WordInfo() {
this.places = new ArrayList<>();
}
public void addPlace(int place) {
this.places.add(place);
}
public int count() {
return this.places.size();
}
public String places() {
if (places.size() == 0)
return "";
String result = "";
for (Integer place : this.places) {
result += ", " + place;
}
result = result.substring(2, result.length());
return result;
}
}
Thanks for trying to help me. -This is what I ended up doing:
import java.util.ArrayList;
import javax.swing.JOptionPane;
public class MyWordCount {
public static void main(String[] args) {
// Text in
String inText = JOptionPane.showInputDialog("Write some text here");
// Puts it into an array, and splits
String[] wordlist = inText.split(" ");
// Text out (Header)
System.out.println("Place:\tWord:\tNo. of Words: ");
// declare Arraylist for words
ArrayList<String> wordEncounter = new ArrayList<String>();
ArrayList<Integer> numberEncounter = new ArrayList<Integer>();
// Checks number of encounters of words
for (int i = 0; i < wordlist.length; i++) {
String word = wordlist[i];
// Make everything lowercase just for ease...
word = word.toLowerCase();
if (wordEncounter.contains(word)) {
// Checks word encounter - return index of word
int position = wordEncounter.indexOf(word);
Integer number = numberEncounter.get(position);
int number_int = number.intValue();
number_int++;
number = new Integer(number_int);
numberEncounter.set(position, number);
// Number of encounters - add 1;
} else {
wordEncounter.add(word);
numberEncounter.add(new Integer(1));
}
}
// Text out (the list of words)
for (int i = 0; i < wordEncounter.size(); i++) {
System.out.println(i + "\t" + wordEncounter.get(i) + "\t"
+ numberEncounter.get(i));
}
}
}

Categories

Resources