Reputation: 627
I'm having an issue with this project. The basic premise is user enters a phrase and it's supposed to find any duplicate words and how many there are.
My issue is when entering just one word multiple times, such as... hello hello hello hello hello
The output for that would be;
"There are 2 duplicates of the word "hello" in the phrase you entered."
"There are 1 duplicates of the word "hello" in the phrase you entered."
This only seems to happen in situations like this. If I enter in a random phrase with multiple words thrown in through out, it displays the correct answer. I think the problem has something to do with removing the duplicate words and how many times it iterates through the phrase, but I just cannot wrap my head around it. I've added print lines everywhere and have changed the times it iterates all sorts of ways, I through it in a Java Visualizer and still couldn't find the exact problem. Any help is greatly appreciated!
This is for an assignment for my online Java course, but it's only for learning/practice it does not go towards my major. I'm not looking for answers though just help.
public class DuplicateWords {
public static void main(String[] args) {
List<String> inputList = new ArrayList<String>();
List<String> finalList = new ArrayList<String>();
int duplicateCounter;
String duplicateStr = "";
Scanner scan = new Scanner(System.in);
System.out.println("Enter a sentence to determine duplicate words entered: ");
String inputValue = scan.nextLine();
inputValue = inputValue.toLowerCase();
inputList = Arrays.asList(inputValue.split("\\s+"));
finalList.addAll(inputList);
for(int i = 0; i < inputList.size(); i++) {
duplicateCounter = 0;
for(int j = i + 1; j < finalList.size(); j++) {
if(finalList.get(i).equalsIgnoreCase(finalList.get(j))
&& !finalList.get(i).equals("!") && !finalList.get(i).equals(".")
&& !finalList.get(i).equals(":") && !finalList.get(i).equals(";")
&& !finalList.get(i).equals(",") && !finalList.get(i).equals("\"")
&& !finalList.get(i).equals("?")) {
duplicateCounter++;
duplicateStr = finalList.get(i).toUpperCase();
}
if(finalList.get(i).equalsIgnoreCase(finalList.get(j))) {
finalList.remove(j);
}
}
if(duplicateCounter > 0) {
System.out.printf("There are %s duplicates of the word \"%s\" in the phrase you entered.", duplicateCounter, duplicateStr);
System.out.println();
}
}
}
}
Based on some suggestions I edited my code, but I'm not sure I'm going in the right direction
String previous = "";
for(Iterator<String> i = inputList.iterator(); i.hasNext();) {
String current = i.next();
duplicateCounter = 0;
for(int j = + 1; j < finalList.size(); j++) {
if(current.equalsIgnoreCase(finalList.get(j))
&& !current.equals("!") && !current.equals(".")
&& !current.equals(":") && !current.equals(";")
&& !current.equals(",") && !current.equals("\"")
&& !current.equals("?")) {
duplicateCounter++;
duplicateStr = current.toUpperCase();
}
if(current.equals(previous)) {
i.remove();
}
}
if(duplicateCounter > 0) {
System.out.printf("There are %s duplicates of the word \"%s\" in the phrase you entered.", duplicateCounter, duplicateStr);
System.out.println();
}
}
Upvotes: 0
Views: 86
Reputation: 424963
Your problem with your code is that when you remove an item, you still increment the index, so you skip over what would be the next item. In abbreviated form, your code is:
for (int j = i + 1; j < finalList.size(); j++) {
String next = finalList.get(i);
if (some test on next)
finalList.remove(next);
}
after remove is called, the "next" item will be at the same index, because removing an item directly like this causes all items to the right to be shuffled 1 place left to fill the gap. To fix, you should add this line after removing:
i--;
That would fix your problem, however, there's a cleaner way to do this:
String previous = "";
for (Iterator<String> i = inputList.iterator(); i.hasNext();) {
String current = i.next();
if (current.equals(previous)) {
i.remove(); // removes current item
}
previous = current;
}
inputList
now has all adjacent duplicates removed.
To remove all duplicates:
List<String> finalList = inputList.stream().distinct().collect(Collectors.toList());
If you like pain, do it "manually":
Set<String> duplicates = new HashSet<>(); // sets are unique
for (Iterator<String> i = inputList.iterator(); i.hasNext();)
if (!duplicates.add(i.next())) // add returns true if the set changed
i.remove(); // removes current item
Upvotes: 1
Reputation: 201399
I would start by populating a Map<String, Integer>
with each word; increment the Integer
each time you encounter a word. Something like
String inputValue = scan.nextLine().toLowerCase();
String[] words = inputValue.split("\\s+");
Map<String, Integer> countMap = new HashMap<>();
for (String word : words) {
Integer current = countMap.get(word);
int v = (current == null) ? 1 : current + 1;
countMap.put(word, v);
}
Then you can iterate the Map
entrySet
and display every key
(word
) where the count is greater than 1
. Something like,
String msgFormat = "There are %d duplicates of the word \"%s\" in "
+ "the phrase you entered.%n";
for (Map.Entry<String, Integer> entry : countMap.entrySet()) {
if (entry.getValue() > 1) {
System.out.printf(msgFormat, entry.getValue(), entry.getKey());
}
}
Upvotes: 1
Reputation: 5262
Before you add inputList
to finalList
, remove any duplicate items from inputList
.
Upvotes: 0