java 从集合中获取随机元素

bvn4nwqk  于 2023-03-21  发布在  Java
关注(0)|答案(9)|浏览(203)

我有一个Collection<Obj>我如何从它得到一个随机的Obj
我已经检查了docs,似乎没有办法,因为迭代器是访问集合的唯一方法。我必须迭代它才能得到一个随机对象吗?

km0tfn4u

km0tfn4u1#

使用Lambdas可以非常快速地完成此操作,并处理Collection为空的情况。

public static <E> Optional<E> getRandom (Collection<E> e) {

    return e.stream()
            .skip((int) (e.size() * Math.random()))
            .findFirst();
}
4szc88ey

4szc88ey2#

最有效的方法是只迭代到你需要的程度。

public 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();
}
4dbbbstv

4dbbbstv3#

private Object getRandomObject(Collection from) {
   Random rnd = new Random();
   int i = rnd.nextInt(from.size());
   return from.toArray()[i];
}
tjvv9vkg

tjvv9vkg4#

我知道这是一个旧的线程,但我很惊讶,没有人提到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
}
jm2pwxwz

jm2pwxwz5#

几个选项(按效率排序):

  • 使用List而不是Collection,
  • 使用random.nextInt(collection.size())生成一个随机索引,获取一个迭代器并进行迭代,
  • 使用random.nextInt(collection.size())生成随机索引,使用toArray()将集合转换为数组,并对该数组进行索引。
js5cn81o

js5cn81o6#

如果您不介意第三方库,Utils库有一个IterableUtils,它有一个randomFrom(Iterable iterable)方法,该方法将接受一个Collection并从中返回一个随机元素

Collection<Object> collection = ....;
Object random = IterableUtils.randomFrom(collection);

它位于Maven中央存储库中,网址为:

<dependency>
  <groupId>com.github.rkumsher</groupId>
  <artifactId>utils</artifactId>
  <version>1.3</version>
</dependency>
wnavrhmk

wnavrhmk7#

使用Google Guava 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)

q9yhzks0

q9yhzks08#

可以将Stream#skipThreadLocalRandom沿着使用。

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"));
}
5fjcxozz

5fjcxozz9#

用户Collections.shuffle(list);。然后你可以只得到第一个元素。它将是随机的。
或者你也可以这样做

int size = list.size();
int item = new Random().nextInt(size); 
list.get(item )

相关问题