【发布时间】:2012-11-21 11:26:18
【问题描述】:
给定一个简单的Set<T>,从Set 获取any 值的好方法是什么(快速、几行代码)?
使用List,很容易:
List<T> things = ...;
return things.get(0);
但是,对于Set,没有.get(...) 方法,因为Sets 没有排序。
【问题讨论】:
给定一个简单的Set<T>,从Set 获取any 值的好方法是什么(快速、几行代码)?
使用List,很容易:
List<T> things = ...;
return things.get(0);
但是,对于Set,没有.get(...) 方法,因为Sets 没有排序。
【问题讨论】:
Set<T> 是 Iterable<T>,因此迭代到第一个元素有效:
Set<T> things = ...;
return things.iterator().next();
Guava 有 a method 来做这件事,虽然上面的 sn-p is likely better.
【讨论】:
iterator().next()。 (这就是为什么我们没有getFirst(Iterable<E>),只有getFirst(Iterable<E>, E default)。)
LinkedHashSet 可以轻松解决。)
由于存在流,你也可以这样做,但你必须使用类java.util.Optional。 Optional 是一个元素或明确无元素的包装类(避免 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) 返回元素,如果不存在,则返回other。 other 可能是 null,顺便说一句。
【讨论】:
set.iterator().next();快还是慢。
从 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 元素。交给我们吧!
【讨论】: