NoobCoderChick
NoobCoderChick

Reputation: 627

Java, removing elements from an ArrayList

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

Answers (3)

Bohemian
Bohemian

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

Elliott Frisch
Elliott Frisch

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

Zamrony P. Juhara
Zamrony P. Juhara

Reputation: 5262

Before you add inputList to finalList, remove any duplicate items from inputList.

Upvotes: 0

Related Questions