我有一个Collection<Obj>
,如何从中获取一个随机的Obj
?
我查看了文档,似乎没有一种方法可以做到这一点,因为迭代器是访问集合的唯一方式。 我必须遍历它才能获得随机对象吗?
使用Lambda表达式可以很快地完成这项任务,并处理集合为空的情况。
public static <E> Optional<E> getRandom (Collection<E> e) {
return e.stream()
.skip((int) (e.size() * Math.random()))
.findFirst();
}
skip((int) (e.size() * Math.random()))
改为 skip(new Random().nextInt(collection.size()))
。 - BitfulBytenextInt
的参数应该大于0。 - Eikthyrnirpublic static <T> T random(Collection<T> coll) {
int num = (int) (Math.random() * coll.size());
for(T t: coll) if (--num < 0) return t;
throw new AssertionError();
}
private Object getRandomObject(Collection from) {
Random rnd = new Random();
int i = rnd.nextInt(from.size());
return from.toArray()[i];
}
0
到 max-1
的范围内。 - Keppil我知道这是一个老话题了,但我很惊讶居然没有人提到RandomAccess
接口,它将List
实现标记为具有非常快速的索引访问。
以下是RandomAccess
的文档:
由List实现使用的标记接口,表示它们支持快速(通常是恒定时间)随机访问。此接口的主要目的是允许通用算法在应用于随机或顺序访问列表时改变其行为以提供良好的性能。
例如: 它是ArrayList
实现的一部分,与LinkedList
不同。
这是我的解决方案,利用了它:
public static <E> E getRandomElement(Collection<E> collection)
{
if(collection.isEmpty())
throw new IllegalArgumentException("Cannot return a random value from an empty collection!");
int randomIndex = ThreadLocalRandom.current().nextInt(collection.size());
if(collection instanceof RandomAccess)
return ((List<E>) collection).get(randomIndex);
for(E element : collection)
{
if(randomIndex == 0)
return element;
randomIndex--;
}
throw new IllegalStateException("How did we get here?"); //unreachable
}
几个选项(按效率顺序):
Collection<Object> collection = ....;
Object random = IterableUtils.randomFrom(collection);
它在Maven中央仓库中:
<dependency>
<groupId>com.github.rkumsher</groupId>
<artifactId>utils</artifactId>
<version>1.3</version>
</dependency>
可以使用 Stream#skip
以及 ThreadLocalRandom
。
public static <T> T getRandomElement(final Collection<T> collection) {
return Objects.requireNonNull(collection, "collection is null").stream()
.skip(ThreadLocalRandom.current().nextInt(Math.max(collection.size(), 1)))
.findFirst().orElseThrow(() -> new IllegalArgumentException("collection is empty"));
}
Iterables.get()
方法的解决方案:private <T> T getRandomObject(Collection<T> from) {
Random rnd = new Random();
int i = rnd.nextInt(from.size());
return Iterables.get(from, i);
}
如果您想处理空集合,可以使用带有defaultValue
的方法: Iterables.get(from, i, null)
使用Collections.shuffle(list);
,然后您只需获取第一个元素即可。它将是随机的。
或者您也可以这样做
int size = list.size();
int item = new Random().nextInt(size);
list.get(item )
random.nextInt(collection.size())
,然后迭代该数字次数。 - Hovercraft Full Of Eels