集合中的相等性<Set> Java

Equality in Set<Set> Java

我有一个方法 returns Set<Set<String>>。在我的测试中,我正在尝试使用 contains() 方法检查预期的 Set 是否存在。

例如。 input = "cat", "dog", "god"

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

现在,如果我 output.contains(new HashSet<>(Arrays.asList("cat"))) 它 return 就会 true

但是如果我这样做 output.contains(new HashSet<>(Arrays.asList("dog", "god"))) 它 returns false.

根据我的理解,这两种情况都应该return true

我在这里错过了什么?

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);
     }
}

当您使用 Set set2 = new HashSet<>(Arrays.asList("god", "dog")); 时,您不是在检查组合 "god" and "dog",而是检查每个元素 god 然后 dog 存在于您的 Set<Set<String>> 或不,并且在你的集合中你只有一个元素 cat 是分开的。就像:

groups contains `god` -> no
groups contains `dog` -> no

return false

要解决您的问题,您可以像这样使用等号:

groups.stream().anyMatch(a -> a.equals(set2))// or groups.stream().anyMatch(set2::equals)

groups.stream().anyMatch(a -> a.containsAll(set2))

问题出在您的 findAndAdd 方法中,您正在改变外部 Set (groups) 的一个元素 (group),因此改变了它的 hashCode()。结果,groups.contains(set2) 找不到 groups 中存在的 Set,因为它在错误的存储桶(匹配新的 hashCode())而不是存储桶中查找它它被添加到其中(匹配原始 hashCode())。

您可以通过在更改 groups 之前删除 group Set 然后重新添加来修复您的代码。

更改您的代码:

 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 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);
 }

当我尝试你的代码并进行更改时,我在两种情况下都得到了 true

输出:

[[cat], [god, dog]]
true
true
[[cat], [god, dog]]

试试这个。

static String sort(String s) {
    int[] sortedCP = s.codePoints().sorted().toArray();
    return new String(sortedCP, 0, sortedCP.length);
}

public static Set<Set<String>> group(Set<String> words) {
    Map<String, Set<String>> map = new HashMap<>();
    for (String word : words)
        map.computeIfAbsent(sort(word), k -> new HashSet<>()).add(word);
    return new HashSet<>(map.values());
}

Set<String> words = new HashSet<>(Arrays.asList("cat", "dog", "god"));
System.out.println(group(words));

结果:

[[cat], [god, dog]]

中间变量map

{act=[cat], dgo=[god, dog]}