【问题标题】:Is there a better way to combine two string sets in java?有没有更好的方法在java中组合两个字符串集?
【发布时间】:2012-01-30 10:39:40
【问题描述】:

我需要在过滤掉冗余信息的同时合并两个字符串集,这是我想出的解决方案,有没有更好的方法可以建议任何人?也许我忽略了一些内置的东西?谷歌没有运气。

Set<String> oldStringSet = getOldStringSet();
Set<String> newStringSet = getNewStringSet();

for(String currentString : oldStringSet)
{
    if (!newStringSet.contains(currentString))
    {
        newStringSet.add(currentString);
    }
}

【问题讨论】:

    标签: java set


    【解决方案1】:

    你可以用这个单线做到这一点

    Set<String> combined = Stream.concat(newStringSet.stream(), oldStringSet.stream())
            .collect(Collectors.toSet());
    

    使用静态导入看起来更好

    Set<String> combined = concat(newStringSet.stream(), oldStringSet.stream())
            .collect(toSet());
    

    另一种方法是使用flatMap方法:

    Set<String> combined = Stream.of(newStringSet, oldStringSet).flatMap(Set::stream)
            .collect(toSet());
    

    任何集合都可以轻松地与单个元素组合

    Set<String> combined = concat(newStringSet.stream(), Stream.of(singleValue))
            .collect(toSet());
    

    【讨论】:

    • 这比 addAll 好多少?
    • @KKlalala,您的要求将决定哪个更好。 addAll 和使用Streams 的主要区别在于: • 使用set1.addAll(set2) 会产生物理上更改set1 内容的副作用。 • 但是,使用 Streams 将始终生成一个新的 Set 实例,其中包含两个集合的内容,而无需修改任何一个原始 Set 实例。恕我直言,这个答案更好,因为它避免了副作用和对原始集合的意外更改的可能性,如果它要在其他地方使用,同时期望原始内容。 HTH
    • 这也有支持Immutable Sets的优势。见:docs.oracle.com/javase/8/docs/api/java/util/…
    • 一个忠告,如果你收集到Set以外的其他东西,添加.distinct(),因为流可以有重复
    【解决方案2】:

    由于Set 不包含重复条目,因此您可以通过以下方式将两者结合起来:

    newStringSet.addAll(oldStringSet);
    

    添加两次都没关系,集合只会包含一次元素......例如不需要使用contains方法检查。

    【讨论】:

      【解决方案3】:

      Guava:

      Set<String> combinedSet = Sets.union(oldStringSet, newStringSet)
      

      【讨论】:

      • Sets::union 是一个很棒的 BinaryOperator,可以与 Collectors.reducing() 一起使用。
      【解决方案4】:

      如果您使用的是 Apache Common,请使用 org.apache.commons.collections4.SetUtils; 中的 SetUtils

      SetUtils.union(setA, setB);
      

      【讨论】:

      • 注意这会返回一个SetView,它是不可变的。
      • 同样,从SetView 获取 size() 始终是线性运算。
      【解决方案5】:

      如果您使用 Guava,您还可以使用构建器来获得更大的灵活性:

      ImmutableSet.<String>builder().addAll(someSet)
                                    .addAll(anotherSet)
                                    .add("A single string")
                                    .build();
      

      【讨论】:

        【解决方案6】:

        从定义 Set 只包含唯一元素。

        Set<String> distinct = new HashSet<String>(); 
         distinct.addAll(oldStringSet);
         distinct.addAll(newStringSet);
        

        为了增强您的代码,您可以为此创建一个通用方法

        public static <T> Set<T> distinct(Collection<T>... lists) {
            Set<T> distinct = new HashSet<T>();
        
            for(Collection<T> list : lists) {
                distinct.addAll(list);
            }
            return distinct;
        }
        

        【讨论】:

          【解决方案7】:

          如果您关心性能,并且不需要保留两个集合并且其中一个可能很大,我建议您检查哪个集合最大并从最小添加元素。

          Set<String> newStringSet = getNewStringSet();
          Set<String> oldStringSet = getOldStringSet();
          
          Set<String> myResult;
          if(oldStringSet.size() > newStringSet.size()){
              oldStringSet.addAll(newStringSet);
              myResult = oldStringSet;
          } else{
              newStringSet.addAll(oldStringSet);
              myResult = newStringSet;
          }
          

          这样,如果你的新集合有 10 个元素,而你的旧集合有 100 000,那么你只做 10 次操作而不是 100 000。

          【讨论】:

          • 这是一个非常好的逻辑,我无法想象为什么这不在主要的 addAll 方法参数中,比如public boolean addAll(int index, Collection&lt;? extends E&gt; c, boolean checkSizes)
          • 我猜是因为规范本身:将指定集合中的所有元素添加到此集合。您确实可以有另一种方法,但如果它不遵循与它重载的方法相同的规范,那将会非常混乱。
          • 是的,我说的是其他方法重载了那个
          【解决方案8】:

          http://docs.oracle.com/javase/7/docs/api/java/util/Set.html#addAll(java.util.Collection)

          由于集合不能有重复,只需将一个的所有元素添加到另一个即可生成两者的正确并集。

          【讨论】:

            【解决方案9】:
             newStringSet.addAll(oldStringSet);
            

            这将产生 s1 和 s2 的联合

            【讨论】:

              【解决方案10】:

              只需使用newStringSet.addAll(oldStringSet)。无需检查重复项,因为 Set 实现已经这样做了。

              【讨论】:

                【解决方案11】:

                使用boolean addAll(Collection&lt;? extends E&gt; c)
                如果指定集合中的所有元素尚不存在,则将它们添加到此集合中(可选操作)。如果指定的集合也是一个集合,那么 addAll 操作会有效地修改这个集合,使其值是两个集合的并集。如果在操作正在进行时修改了指定的集合,则此操作的行为是未定义的。

                newStringSet.addAll(oldStringSet)
                

                【讨论】:

                  【解决方案12】:
                  Set.addAll()
                  

                  如果指定集合中的所有元素尚不存在,则将它们添加到此集合中(可选操作)。如果指定的集合也是一个集合,那么 addAll 操作会有效地修改这个集合,使其值是两个集合的并集

                  newStringSet.addAll(oldStringSet)
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2019-11-29
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多