【问题标题】:Equality in Set<Set> JavaSet<Set> Java 中的相等性
【发布时间】:2018-11-21 19:02:06
【问题描述】:

我有一个返回Set&lt;Set&lt;String&gt;&gt; 的方法。在我的测试中,我试图使用contains() 方法检查预期的Sets 是否存在。

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

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

现在,如果我执行output.contains(new HashSet&lt;&gt;(Arrays.asList("cat"))),它会返回true

但如果我执行output.contains(new HashSet&lt;&gt;(Arrays.asList("dog", "god"))),它会返回false

根据我的理解,这两种情况都应该返回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);
     }
}

【问题讨论】:

    标签: java string set equals contains


    【解决方案1】:

    问题出在您的 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]]
    

    【讨论】:

    • @Eran 非常感谢!
    【解决方案2】:

    当您使用Set set2 = new HashSet&lt;&gt;(Arrays.asList("god", "dog")); 时,您不会检查"god" and "dog" 的组合,而是检查god 的每个元素然后dog 是否存在于您的Set&lt;Set&lt;String&gt;&gt; 中,并且在您的集合中您只有一个元素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))
    

    【讨论】:

    • new HashSet&lt;&gt;(Arrays.asList("cat", "god", "dog")) 创建的Set 不是调用groups.contains(set2)SetgroupsAnagramGroups 生成,它将“dog”和“god”字符串分组在同一个内部Set中。
    【解决方案3】:

    试试这个。

    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]}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-24
      • 2015-10-20
      • 1970-01-01
      • 1970-01-01
      • 2018-12-16
      • 2015-06-27
      • 1970-01-01
      相关资源
      最近更新 更多