【问题标题】:Good way to get *any* value from a Java Set?从 Java Set 中获取 *any* 值的好方法?
【发布时间】:2012-11-21 11:26:18
【问题描述】:

给定一个简单的Set<T>,从Set 获取any 值的好方法是什么(快速、几行代码)?

使用List,很容易:

List<T> things = ...;
return things.get(0);

但是,对于Set,没有.get(...) 方法,因为Sets 没有排序。

【问题讨论】:

    标签: java set any


    【解决方案1】:

    Set&lt;T&gt;Iterable&lt;T&gt;,因此迭代到第一个元素有效:

    Set<T> things = ...;
    return things.iterator().next();
    

    Guava 有 a method 来做这件事,虽然上面的 sn-p is likely better.

    【讨论】:

    • 实际上,当您不想要默认值时,我们希望您继续使用iterator().next()。 (这就是为什么我们没有getFirst(Iterable&lt;E&gt;),只有getFirst(Iterable&lt;E&gt;, E default)。)
    • @LouisWasserman:不一定。如果集合非常大,并且删除了大部分项目,则需要循环直到找到一个非空桶。 stackoverflow.com/a/3046838/34397
    • 正确,但在实践中极为罕见。 (另外,使用LinkedHashSet 可以轻松解决。)
    • (另外,我声称不存在更快的解决方案。)
    【解决方案2】:

    由于存在流,你也可以这样做,但你必须使用类java.util.OptionalOptional 是一个元素或明确无元素的包装类(避免 Nullpointer)。

    //returns an Optional.
    Optional <T> optT = set.stream().findAny();
    
    //Optional.isPresent() yields false, if set was empty, avoiding NullpointerException
    if(optT.isPresent()){
        //Optional.get() returns the actual element
        return optT.get();
    }
    

    编辑: 因为我自己经常使用Optional:有一种方法可以访问元素或获取默认值,以防它不存在:
    optT.orElse(other) 返回元素,如果不存在,则返回otherother 可能是 null,顺便说一句。

    【讨论】:

    • 不知道这比set.iterator().next();快还是慢。
    • set.iterator().next() 将抛出 NoSuchElementException 以防集合为空,使用 findAny of Stream 更安全,因为如果集合为空,它将为您提供一个空的 Optional。除非性能真的很重要,否则我会在安全方面犯错。真的取决于你需要什么。
    【解决方案3】:

    从 Set 或 Collection 中获取 any 元素似乎是一种不常见的需求 - 如果不是任意的或不拘一格的 - 但是,例如,当需要计算 统计信息时,这是很常见的在 Map 中的 Keys 或 Values 对象上,并且必须初始化最小/最大值。 Set/Collection 中的 any 元素(由 Map.keySet() 或 Map.values() 返回)将在更新 each 上的最小/最大值之前用于此初始化em> 元素。

    那么,当面对这个问题,同时又要尽量减少内存和执行时间以及代码清晰时,有哪些选择?

    通常你会得到通常的:“将 Set 转换为 ArrayList 并获取第一个元素”。伟大的!另一个包含数百万个项目的数组和额外的处理周期,用于从 Set、allocate 数组和 populate检索 对象:

    HashMap<K,V> map;
    List<K> list = new ArrayList<V>(map.keySet()); // min/max of keys
    min = max = list.get(0).some_property(); // initialisation step
    for(i=list.size();i-->1;){
     if( min > list.get(i).some_property() ){ ... }
     ...
    }
    

    或者可以使用带有迭代器的循环,使用标志来表示需要初始化最小值/最大值,并使用条件语句检查是否为循环中的所有迭代设置了该标志。这意味着大量的条件检查。

    boolean flag = true;
    Iterator it = map.keySet().iterator();
    while( it.hasNext() ){
      if( flag ){
        // initialisation step
        min = max = it.next().some_property();
        flag = false;
      } else {
        if( min > list.get(i).some_property() ){ min = list.get(i).some_property() }
      ...
      }
    }
    

    或者在循环外进行初始化:

    HashMap<K,V> map;
    Iterator it = map.keySet().iterator();
    K akey;
    if( it.hasNext() ){
      // initialisation step:
      akey = it.next();
      min = max = akey.value();
      do {
        if( min > list.get(i).some_property() ){ min = akey.some_property() }
      } while( it.hasNext() && ((akey=it.next())!=null) );
    }
    

    但是在需要 min/max 时代表程序员(并代表 JVM 设置迭代器)真的值得所有这些操作吗?

    一个 javally 正确的 ol' 运动的建议很可能是:“将您的地图包装在一个类中,该类在放置或删除时跟踪最小值和最大值!”。

    还有另一种情况,根据我的经验,需要地图中的任何项。 这是指地图包含具有共同属性的对象 - 该地图中的所有对象都相同 - 您需要阅读该属性。例如,假设有一个具有相同直方图的存储箱的地图,这些箱具有相同的维数。给定这样的地图,您可能需要知道地图中 any Histobin 的维数,以便创建另一个相同维度的 Histobin。我是否需要再次设置一个迭代器并在调用 next() 一次后处理它?对于这种情况,我将跳过 javally-correct 人的建议。

    如果获取 any 元素的所有麻烦都会导致内存不足和 CPU 周期增加,那么为了获取难以获取的元素而必须编写的所有代码呢?任何元素。

    我们需要 any 元素。交给我们吧!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-02
      • 1970-01-01
      • 1970-01-01
      • 2014-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-29
      相关资源
      最近更新 更多