Can't figure out what's triggering "java.util.ConcurrentModificationException" - java

My code is throwing an error that I've never seen before. So hey! I guess I'm learning ;) Anyway, I did some reading and generally this error is thrown when a list that is being iterated over is modified mid-iteration. However, I'm pretty sure I'm not modifying it. While the error is being thrown on partition(), if I don't assign a new value for currentList in updateCurrentList() (by commenting out the code), the program no longer throws the error. These two functions are called one after the other in my play() method, however the list iteration should be complete by the time the change is made. What am I missing? Do I have to close down the iterator somehow?
package hangman;
import java.io.*;
import java.util.*;
import javax.swing.JOptionPane;
public class Hangman {
private Map<String, List<String>> wordPartitions; // groups words according to positions of guessed letter
private List<String> currentList; // remaining possible words that fit the information given so far
Set<Character> wrongGuesses; // holds all the "wrong" guesses so far
StringBuilder guessString; // current state of the word being guessed
String justHyphens; // for checking whether a guess was "wrong"
// initialize fields
// currentList should contain all (and only) words of length wordLength
// justHyphens and guessString should consist of wordLength hyphens
public Hangman(int wordLength) throws FileNotFoundException {
this.currentList = new ArrayList<String>();
addWords(wordLength);
wrongGuesses = new HashSet();
for(int i = 0; i < wordLength; i++) {
justHyphens += "-";
}
guessString = new StringBuilder();
wordPartitions = new HashMap();
}
private void addWords(int wordLength) throws FileNotFoundException {
Scanner words = new Scanner(new File("lexicon.txt"));
String word = "";
while(words.hasNext()) {
word = words.next();
if (word.length() == wordLength) {
currentList.add(word);
}
}
}
// main loop
public void play() {
char choice;
do {
choice = getUserChoice();
partition(choice);
updateCurrentList(choice);
} while (!gameOver());
endMessage();
}
// display the guessString and the missed guesses
// and get the next guess
private char getUserChoice() {
//generate a string from the incorrect choices char list
String wrong = "";
char letter;
if(!wrongGuesses.isEmpty()) {
Iterator<Character> letters = wrongGuesses.iterator();
letter = letters.next();
while(letters.hasNext()) {
letter = letters.next();
wrong += ", " + letter;
}
}
String letterStr = JOptionPane.showInputDialog("Incorrect choices: "+ wrong +"\n Tested letters: "+ guessString.toString() +"\nplease input a letter.");
return letterStr.charAt(0);
}
// use wordPartitions to partition currentList using
// keys returned by getPartitionKey()
private void partition(char choice) {
String word = "";
String key = "";
List<String> tempList = new ArrayList<String>();
Iterator<String> words = currentList.iterator();
//Generate a key for each word and add to appropriate arraylist within map.
while(words.hasNext()) {
word = words.next();
key = getPartitionKey(word, choice);
if(wordPartitions.containsKey(key)) {
tempList = wordPartitions.get(key);
tempList.add(word);
wordPartitions.put(key, tempList);
} else {
tempList.clear();
tempList.add(word);
wordPartitions.put(key, new ArrayList<String>());
}
}
}
// update currentList to be a copy of the longest partition
// if choice was "wrong", add choice to wrongGuesses
// if choice was "right", update guessString
private void updateCurrentList(char choice) {
String key = findLongestList();
currentList = wordPartitions.get(key);
if(key.equals(justHyphens)) {
wrongGuesses.add(choice);
} else {
addLetterToGuessString(guessString, choice, key);
}
}
private String findLongestList() {
Set<String> keySet = wordPartitions.keySet();
Iterator<String> keys = keySet.iterator();
String maxKey = "";
int maxKeyLength = 0;
List<String> tempList;
String tempKey = "";
while(keys.hasNext()) {
tempKey = keys.next();
tempList = wordPartitions.get(tempKey);
if(tempList.size() > maxKeyLength) {
maxKeyLength = tempList.size();
maxKey = tempKey;
}
}
return maxKey;
}
// checks for end of game
private boolean gameOver() {
return false;
}
// display the guessString and the missed guesses
// and print "Congratulations!"
private void endMessage() {
JOptionPane.showMessageDialog(null, "Congrats, yo!");
}
// returns string with '-' in place of each
// letter that is NOT the guessed letter
private String getPartitionKey(String s, char c) {
String word = "";
String letter = Character.toString(c);
for(int i = 0; i < s.length(); i++) {
if(s.charAt(i) == c) {
word += letter;
} else {
word += "-";
}
}
return word;
}
// update guessString with the guessed letter
private void addLetterToGuessString(StringBuilder guessString, char letter, String key) {
for(int i = 0; i < key.length(); i++) {
if(key.charAt(i) != '-') {
guessString.setCharAt(i, key.charAt(i));
}
}
}
}

The problem is that you are modifying a collection while you are iterating over it.
The collection is currentList, you are iterating over it in partition(). You modify it when you add a word to tempList here:
key = getPartitionKey(word, choice);
if(wordPartitions.containsKey(key)) {
tempList = wordPartitions.get(key);
tempList.add(word);
wordPartitions.put(key, tempList);
} else {
Why ? Because previously you called updateCurrentList() from play():
do {
choice = getUserChoice();
partition(choice);
updateCurrentList(choice);
} while (!gameOver());
And you updated currentList:
String key = findLongestList();
currentList = wordPartitions.get(key);
So, if the key returned by getPartitionKey(word, choice) is the same as the key previously returned by findLongestList(), currentListwill be the same as tempList, and so you will be modifying the collection you are iterating over.
The solution ? If tempList is the same as currentList, don't add the word to it (it already have the word, by definition). So, you can rewrite your if-else like that (I removed some useless code):
if(wordPartitions.containsKey(key)) {
tempList = wordPartitions.get(key);
} else {
wordPartitions.put(key, new ArrayList<String>());
}
if (tempList!=currentList) {
tempList.add(word);
}

Related

Ordination of vowels of a sentence in descending order

Suppose I enter the following string:
" Hello party"
How could you order only the vowels of that chain, but in a descending way?
to example:
"Halle porty"
In the following way I have tried to solve the problem, but when I run it tells me that I have an ExeptionBounce 5. How could I correct it? I am also told that the responsible line is the following:
if(cad[i].equalsIgnoreCase(vocal[j])
private String[]cad;
private String[]vocal={"a","e","i","o","u"};
private String resp="";
private String aux="":
private String []sort;
private int cont=0;
public String ordenar(String cadena)
{
cad= cadena.split("");
for(int i=0; i<cad.legth; i++)
{
for(int j=i, j<vocal.legth; j++)
{
if(cad[i].equalsIgnoreCase(vocal[j])
{
aux+=cad[i];
sort= aux.Split("");
Arrays.sort(sort);
for(int i=0; i<cad.legth; i++)
{
cad[i] = sort[k];
resp+=cad[i];
}
}
}
return resp;
}
Your code would not even compile - how are you running it ?
To answer your question, here is a piece of code which given a string will return the string with the vowels sorted:
public static boolean isVowel(char c) {
return "AEIOUaeiou".indexOf(c) != -1;
}
public static String sortVowelsOnly(String input) {
if (input == null) {
return input;
}
StringBuilder result = new StringBuilder(input);
//keep track at all positions where we saw a vowel
ArrayList<Integer> vowelPositions = new ArrayList<>();
//keep track of all vowels we saw so far
ArrayList<Character> vowels = new ArrayList<>();
for (int charPosition = 0; charPosition < input.length(); charPosition++) {
char currentChar = input.charAt(charPosition);
if(isVowel(currentChar)) {
vowelPositions.add(charPosition);
vowels.add(currentChar);
}
}
Collections.sort(vowels);
//now just iterate over all positions where we saw a vowel, and populate it with the vowels from the sorted list
for(Integer vowelPosition : vowelPositions) {
char vowel = vowels.remove(0);
result.setCharAt(vowelPosition, vowel);
}
return result.toString();
}

Isogram- a word without repeated letters

I want to develop a java code to detect a repeated letter in word and print the desired result but mine keeps iterating and i have no idea on how to get about it. Here is the code:
import java.util.*;
public class Isogram {
public static void main(String[] args){
Scanner input = new Scanner(System.in);
System.out.println("Enter the name: ");
String car = input.nextLine().toLowerCase();
char[] jhd = car.toCharArray();
Arrays.sort(jhd);
for(int ch = 0; ch < jhd.length; ch++){
try {
if (jhd[ch] == jhd[ch + 1]) {// || jhd[ch] == jhd[ch]){
System.out.print("THis is an Isogram");
} else {
System.out.println("Ripu from here");
}
} catch(ArrayIndexOutOfBoundsException ae) {
System.out.println(ae);
}
}
}
}
If u have an adjustment or a better code it will be helpful.
private static String isIsogram(String s){
String[] ary = s.split("");
Set<String> mySet = new HashSet<String>(Arrays.asList(ary));
if(s.length() == mySet.size()){
return "Yes!";
}else{
return "NO";
}
}
Create an array from the string.
Convert array to a List and then create a Set from that List. Set
keeps only unique values.
If set size equals the initial string length then it is an
isogram. If set is smaller than initial string then there were
duplicate characters.
public static boolean isIsogram(String str) {
boolean status = true;
char [] array = str.toCharArray();
Character[] charObjectArray = ArrayUtils.toObject(array);
Map<Character,Integer> map = new HashMap<>();
for (Character i : charObjectArray){
Integer value = 1;
if (map.containsKey(i)){
Integer val = map.get(i);
map.put(i,val+1);
}
else map.put(i,value);
}
for (Integer integer: map.values()){
if (integer>1){
status= false;
break;
}
else status = true;
}
return status;
}
}

Evil Hangman Java Program

I am working on a Evil Hangman Program And for some reason I am getting this error:
What length word do you want to use? 4
How many wrong answers allowed? 4
guesses : 4
guessed : []
current : ----
Your guess? e
Exception in thread "main" java.lang.NullPointerException
at Game.HangmanManager.record(HangmanManager.java:142)
at Game.HangmanMain.playGame(HangmanMain.java:62)
at Game.HangmanMain.main(HangmanMain.java:42)
Here is my program:
package Game;
import java.util.*;
public class HangmanManager
{
private String pattern;
private int max;
private int length;
private SortedSet<Character> guessesMade;
private Set<String> currentWords;
private Map<String, Set<String>> patternMap;
public HangmanManager(List<String> dictionary , int length, int max)
{
this.max = max;
this.length = length;
if( length < 1 && max < 0)
{
throw new IllegalArgumentException();
}
words = new TreeSet<String>();
guessesMade = new TreeSet<Character>();
currentWords = new TreeSet<String>(); // current words =(words)
patternMap = new TreeMap<String, Set<String>>(); // patternMAP = < pattern, words>
for (String word : dictionary)
{
if (word.length() == length)
{
words.add(word); // if length of the word matches a word with the same length it will be added
}
}
}
public Set<String> words()
{
return words;
}
public int guessesLeft()
{
return max - guessesMade.size();
}
public SortedSet<Character> guesses()
{
return guessesMade;
}
public String pattern()
{
if (words.isEmpty())
{
throw new IllegalArgumentException("Invalid No Words");
}
pattern = " "; // blank for now
for (int i = 0; i < length; i++)
{
pattern += "-"; // will have a "-" for how long the length of the word is
}
return pattern; // will return the number of lines
}
public int record(char guess)
{
if (guessesLeft() < 1 || words.isEmpty())
{
throw new IllegalStateException();
}
if (!words.isEmpty() && guessesMade.contains(guess))
{
throw new IllegalArgumentException();
}
guessesMade.add(guess); // guess
int occurences = 0;
for( String word: words)
{
if( patternMap.containsKey (pattern))
{
occurences = generatePattern(word, guess); // the word including the guess letter will fill in the blank spots
currentWords.add(word); // the word will be added to the possibilities
currentWords = patternMap.get(pattern); // the word will be able to fill once the guesses are made
// if(patternMap.get(pattern)!=null)
// {
// currentWords = patternMap.get(pattern);
//
// }
patternMap.put(pattern, currentWords);
}
else
{
currentWords.add(word);
patternMap.put(pattern, currentWords);
}
}
words = find();
return occurences;
}
private Set<String> find()
{
int maxSize = 0;
Map <String, Integer> patternCount = new TreeMap<String, Integer>();
for (String key : patternMap.keySet()) // keyset equals word
{
patternCount.put(key, patternMap.get(key).size()); // size of the word
if (patternMap.get(key).size() > maxSize)
{
maxSize = patternMap.get(key).size();
pattern = key; // pattern will becomes based on the word
} else if (patternMap.get(key).size() == maxSize)
{
if (key.length() >= pattern.length())
{
pattern = key;
maxSize = patternMap.get(key).size(); // the pattern is now the word key
}
}
}
System.out.println("Current pattern: " + pattern);
return patternMap.get(pattern); // the pattern that will becomes now that the word was picked
}
private int generatePattern(String s, char guess)
{
int count = 0;
pattern = "";
for (int i = 0; i < length; i++)
{
if (s.charAt(i) == guess)
{
pattern += guess + " ";
count++;
} else
{
pattern += "- ";
}
}
return count;
}
}
The error seems to happen in the record method for the :
patternMap.put(pattern, currentWords); on Line 149
I ran the debugger numerous times and I do notice that if you follow the program you will see that currentWords becomes Null eventually after the program runs through the words after one time even though I instantiate it and I created a Map for patternMap.
If anyone can tell me what to do or what to change I will really appreciate it because I am so lost with this
patternMap is a TreeMap. As you said, your problem is with patternMap.put(pattern, currentWords); on line 149. According to the JavaDocs for TreeMap, put() throws NullPointerException...
if the specified key is null and this map uses natural ordering, or its comparator does not permit null keys
Since a TreeMap<String,Object> uses natural ordering of it's keys (i.e. String), the problem is that pattern is null. Why don't you just initialize pattern to a default value:
private String pattern = " ";

Ordering java linked list alphabetically (dictionary-like)

I've been working for hours trying to order a linked list of strings alphabetically (dictionary-like). The given string is lowercase only.
For example, input of: "hello my name is albert" will be sorted in the list as: Node 1: albert,
Node 2: hello,
Node 3: is,
etc..
My code so far reads a string like the example above and insert it as nodes - unordered.
I've searched in the web for ways to sort a linked list alphabetically with good performance, and I found Merge Sort can be usefull.
I've changed the merge sort to work for string using compareTo() but my code returns nullPointerException error in the following line:
if(firstList._word.compareTo(secondList._word) < 0){
I'm looking for help to fix the following code or another way for sorting a linked list alphabetically (without Collection.sort)
My full code is (after trying to add the merge sort to work with my code):
public class TextList
{
public WordNode _head;
public TextList()
{
_head = null;
}
public TextList (String text)
{
this._head = new WordNode();
int lastIndex = 0;
boolean foundSpace = false;
String newString;
WordNode prev,next;
if (text.length() == 0) {
this._head._word = null;
this._head._next = null;
}
else {
for (int i=0;i<text.length();i++)
{
if (text.charAt(i) == ' ') {
newString = text.substring(lastIndex,i);
insertNode(newString);
// Update indexes
lastIndex = i;
// set to true when the string has a space
foundSpace = true;
}
}
if (!foundSpace) {
//If we didnt find any space, set the given word
_head.setWord(text);
_head.setNext(null);
}
else {
//Insert last word
String lastString = text.substring(lastIndex,text.length());
WordNode lastNode = new WordNode(_head._word,_head._next);
_head.setNext(new WordNode(lastString,lastNode));
}
sortList(_head);
}
}
private void insertNode(String word)
{
//Create a new node and put the curret node in it
WordNode newWord = new WordNode(_head._word,_head.getNext());
//Set the new information in the head
_head._word = word;
_head.setNext(newWord);
}
private WordNode sortList(WordNode start) {
if (start == null || start._next == null) return start;
WordNode fast = start;
WordNode slow = start;
// get in middle of the list :
while (fast._next!= null && fast._next._next !=null){
slow = slow._next; fast = fast._next._next;
}
fast = slow._next;
slow._next=null;
return mergeSortedList(sortList(start),sortList(fast));
}
private WordNode mergeSortedList(WordNode firstList,WordNode secondList){
WordNode returnNode = new WordNode("",null);
WordNode trackingPointer = returnNode;
while(firstList!=null && secondList!=null){
if(firstList._word.compareTo(secondList._word) < 0){
trackingPointer._next = firstList; firstList=firstList._next;
}
else {
trackingPointer._next = secondList; secondList=secondList._next
;}
trackingPointer = trackingPointer._next;
}
if (firstList!=null) trackingPointer._next = firstList;
else if (secondList!=null) trackingPointer._next = secondList;
return returnNode._next;
}
public String toString() {
String result = "";
while(_head.getNext() != null){
_head = _head.getNext();
result += _head._word + ", ";
}
return "List: " + result;
}
public static void main(String[] args) {
TextList str = new TextList("a b c d e a b");
System.out.println(str.toString());
}
}
In the past i have made a method to sort strings alphabetically in an array as school HW, so umm here it is:
private void sortStringsAlphabetically(){
for (int all = 0; all < names.length; all++) {
for (int i = all + 1; i < names.length; i++) {
if (names[all].compareTo(names[i]) > 0) {
String tmp = names[i];
names[i] = names[all];
names[all] = tmp;
}
}
}
}
This piece of code works for Arrays and specifically for an array of names. You can tweak it to work with the list, it is very simple especially if we consider the wide range of methods in the List interface and all it's implementations.
Cheers.
If you don't wanna to have a huge code who gets every first letter of the word and sort them, do it with Collection.sort()
I don't know what is the proplem on Collection.sort() so use it
Here is a short code, that does exactually this what you want to:
String test = "hello my name is albert";
test = test.replaceAll(" ", "\n");
String[] te = test.split("\n");
List<String> stlist = new ArrayList<String>();
for(String st : te) {
stlist.add(st);
}
Collections.sort(stlist);
Regarding NPE you said it is probably because you are having an null string in head at first and keep adding this in insert method.
this._head = new WordNode();
Also the adding last element is also not proper. Just reuse the insert method like below
insertNode(text.substring(lastIndex,text.length()));
These are the ones I thought having problem when you are converting string to lined list
You can use the below code to handle the first null
private void insertNode(String word) {
if (this._head == null) {
this._head = new WordNode(word, null);
} else {
WordNode newWord = new WordNode(_head._word, _head.getNext());
_head._word = word;
_head.setNext(newWord);
}
}

counting unique words in a string without using an array

So my task is to write a program that counts the number of words and unique words in a given string that we get from the user without using arrays.
I can do the first task and was wondering how I could go about doing the second part.
For counting the number of words in the string I have
boolean increment = false;
for (int i = 0; i < inputPhrase.length(); i++){
if(validChar(inputPhrase.charAt(i))) //validChar(char c) is a simple method that returns a valid character{
increment = true;
}
else if(increment){
phraseWordCount ++;
increment = false;
}
}
if(increment) phraseWordCount++; //in the case the last word is a valid character
(originally i left this out and was off by one word)
to count unique words can I somehow modify this?
Here a suggestion how to do it without arrays:
1) Read every char until a blank is found and add this char to a second String.
2) If a blank is found, add it (or another token to seperate words) to the second String.
2a) Read every word from second String comparing it to the current word from he input String
public static void main(String[] args) {
final String input = "This is a sentence that is containing three times the word is";
final char token = '#';
String processedInput = "";
String currentWord = "";
int wordCount = 0;
int uniqueWordCount = 0;
for (char c : input.toCharArray()) {
if (c != ' ') {
processedInput += c;
currentWord += c;
} else {
processedInput += token;
wordCount++;
String existingWord = "";
int occurences = 0;
for (char c1 : processedInput.toCharArray()) {
if (c1 != token) {
existingWord += c1;
} else {
if (existingWord.equals(currentWord)) {
occurences++;
}
existingWord = "";
}
}
if (occurences <= 1) {
System.out.printf("New word: %s\n", currentWord);
uniqueWordCount++;
}
currentWord = "";
}
}
wordCount++;
System.out.printf("%d words total, %d unique\n", wordCount, uniqueWordCount);
}
Output
New word: This
New word: is
New word: a
New word: sentence
New word: that
New word: containing
New word: three
New word: times
New word: the
New word: word
12 words total, 10 unique
Using the Collections API you can count words with the following method:
private int countWords(final String text) {
Scanner scanner = new Scanner(text);
Set<String> uniqueWords = new HashSet<String>();
while (scanner.hasNext()) {
uniqueWords.add(scanner.next());
}
scanner.close();
return uniqueWords.size();
}
If it is possible that you get normal sentences with punctuation marks you can change the second line to:
Scanner scanner = new Scanner(text.replaceAll("[^0-9a-zA-Z\\s]", "").toLowerCase());
Every time a word ends findUpTo checks if the word is contained in the input before the start of that word. So "if if if" would count as one unique and three total words.
/**
* Created for http://stackoverflow.com/q/22981210/1266906
*/
public class UniqueWords {
public static void main(String[] args) {
String inputPhrase = "one two ones two three one";
countWords(inputPhrase);
}
private static void countWords(String inputPhrase) {
boolean increment = false;
int wordStart = -1;
int phraseWordCount = 0;
int uniqueWordCount = 0;
for (int i = 0; i < inputPhrase.length(); i++){
if(validChar(inputPhrase.charAt(i))) { //validChar(char c) is a simple method that returns a valid character{
increment = true;
if(wordStart == -1) {
wordStart = i;
}
} else if(increment) {
phraseWordCount++;
final String lastWord = inputPhrase.substring(wordStart, i);
boolean unique = findUpTo(lastWord, inputPhrase, wordStart);
if(unique) {
uniqueWordCount++;
}
increment = false;
wordStart = -1;
}
}
if(increment) {
phraseWordCount++; //in the case the last word is a valid character
final String lastWord = inputPhrase.substring(wordStart, inputPhrase.length());
boolean unique = findUpTo(lastWord, inputPhrase, wordStart);
if(unique) {
uniqueWordCount++;
}
}
System.out.println("Words: "+phraseWordCount);
System.out.println("Unique: "+uniqueWordCount);
}
private static boolean findUpTo(String needle, String haystack, int lastPos) {
boolean previousValid = false;
boolean unique = true;
for(int j = 0; unique && j < lastPos - needle.length(); j++) {
final boolean nextValid = validChar(haystack.charAt(j));
if(!previousValid && nextValid) {
// Word start
previousValid = true;
for (int k = 0; k < lastPos - j; k++) {
if(k == needle.length()) {
// We matched all characters. Only if the word isn't finished it is unique
unique = validChar(haystack.charAt(j+k));
break;
}
if (needle.charAt(k) != haystack.charAt(j+k)) {
break;
}
}
} else {
previousValid = nextValid;
}
}
return unique;
}
private static boolean validChar(char c) {
return Character.isAlphabetic(c);
}
}

Categories