Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Equality in Set<Set> Java

I have a method that returns Set<Set<String>>. In my test, I am trying to check if the expected Sets are present using contains() method.

eg. input = "cat", "dog", "god"

output = [[cat], [dog, god]]

Now, if I do output.contains(new HashSet<>(Arrays.asList("cat"))) it returns true.

But if I do output.contains(new HashSet<>(Arrays.asList("dog", "god"))) it returns false.

According to my understanding, it should return true in both cases.

What am I missing here?

public class AnagramGroups {
     public Set<Set<String>> group(Set<String> words) {
         Set<Set<String>> groups = new HashSet<>();
         for(String word: words) {
             findAndAdd(word, groups);
         }
         return groups;
     }

     private void findAndAdd(String word, Set<Set<String>> groups) {
         for(Set<String> group: groups) {
             boolean found = false;
             for(String str: group) {
                 if(isAnagram(str, word)) {
                     found = true;
                 }
                 break;
             }
             if(found) {
                 group.add(word);
                 return;
             }
         }
         Set<String> set = new HashSet<>();
         set.add(word);
         groups.add(set);
     }

     private boolean isAnagram(String str, String word) {
         Set<Character> characters = new HashSet<>();
         for(char c: str.toCharArray()) {
             characters.add(c);
         }
         for(char c: word.toCharArray()) {
             if(!characters.contains(c)) {
                 return false;
             }
             characters.remove(c);
         }
         return characters.isEmpty();
     }

     public static void main(String[] args) {
         Set<Set<String>> groups = new AnagramGroups()
             .group(new HashSet<>(Arrays.asList("cat", "god", "dog")));
         System.out.println(groups);

         Set set1 = new HashSet<>(Arrays.asList("cat"));
         Set set2 = new HashSet<>(Arrays.asList("god", "dog"));
         System.out.println(groups.contains(set1));
         System.out.println(groups.contains(set2));

         groups.add(new HashSet<>(Arrays.asList("god", "dog")));
         System.out.println(groups);
     }
}
like image 274
rucha kulkarni Avatar asked Jun 12 '18 11:06

rucha kulkarni


People also ask

Can we compare 2 sets in Java?

So, the equals() method is one of the most used and fast ways to compare two sets in Java. The equals() method compares two sets based on the type of the elements, size of the set, and value of the elements.

How do you find the equality of a set?

Definition 2: Two sets A and B are said to be equivalent if they have the same cardinality i.e. n(A) = n(B). In general, we can say, two sets are equivalent to each other if the number of elements in both the sets is equal. And it is not necessary that they have same elements, or they are a subset of each other.

What is a set <> in Java?

Set in Java is an interface declared in java. util package. It extends the collection interface that allows creating an unordered collection or list, where duplicate values are not allowed. As the name implies, a set in Java is used to create a mathematical set.

How do you compare two hash sets?

The equals() method of java. util. HashSet class is used verify the equality of an Object with a HashSet and compare them. The list returns true only if both HashSet contains same elements, irrespective of order.


1 Answers

The issue is in your findAndAdd method, where you are mutating an element (group) of the outer Set (groups), therefore changing its hashCode(). As a result, groups.contains(set2) cannot find a Set that is present in groups, since it looks for it in the wrong bucket (matching the new hashCode()) instead of the bucket to which it was added (matching the original hashCode()).

You can fix your code by removing the group Set from groups before mutating it and then re-add it.

Change your code from:

 private void findAndAdd(String word, Set<Set<String>> groups) {
     for(Set<String> group: groups) {
         boolean found = false;
         for(String str: group) {
             if(isAnagram(str, word)) {
                 found = true;
             }
             break;
         }
         if(found) {
             group.add(word);
             return;
         }
     }
     Set<String> set = new HashSet<>();
     set.add(word);
     groups.add(set);
 }

to:

 private void findAndAdd(String word, Set<Set<String>> groups) {
     for(Set<String> group: groups) {
         boolean found = false;
         for(String str: group) {
             if(isAnagram(str, word)) {
                 found = true;
             }
             break;
         }
         if(found) {
             groups.remove(group);
             group.add (word);
             groups.add(group);
             return;
         }
     }
     Set<String> set = new HashSet<>();
     set.add(word);
     groups.add(set);
 }

When I tried your code and made that change, I got true in both cases.

Output:

[[cat], [god, dog]]
true
true
[[cat], [god, dog]]
like image 132
Eran Avatar answered Oct 29 '22 13:10

Eran