从集合中获取随机元素

时间:2014-01-13 13:06:22

标签: java

我有Collection<Obj>如何从中获取随机Obj

我检查了docs并且似​​乎没有办法,因为迭代器是访问集合的唯一方法。我是否必须迭代它以获得随机对象!?

9 个答案:

答案 0 :(得分:23)

最有效的只能根据需要进行迭代。

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

答案 1 :(得分:23)

使用Lambdas,您可以非常快速地执行此操作,并在Collection为空时处理案例。

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

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

答案 2 :(得分:6)

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

答案 3 :(得分:1)

几种选择(按效率顺序):

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

答案 4 :(得分:1)

我知道这是一个旧线程,但是令我惊讶的是,没有人提到RandomAccess接口,该接口没有方法,并且标记为List实现的索引访问非常快。

这是RandomAccess的文档:

List实现使用的

Marker接口表示它们支持快速(通常为恒定时间)随机访问。此接口的主要目的是允许通用算法更改其行为,以便在应用于随机或顺序访问列表时提供良好的性能。

它是由ArrayList实现的,而不是由LinkedList实现的。

这是我利用它的解决方案:

public static <E> E getRandomElement(Collection<E> collection) 
{
    if(collection.isEmpty()) 
    {
        return null;
    }
    int randomIndex = ThreadLocalRandom.current().nextInt(collection.size());

    if(collection instanceof RandomAccess) 
    {
        List<E> list = (List<E>) collection;
        
        return list.get(randomIndex);
    }
    else 
    {
        for(E element : collection)
        {
            if(randomIndex == 0)
            {
                return element;
            }
            randomIndex--;
        }
        return null; //unreachable
    }
}

答案 5 :(得分:0)

如果您不介意第三方库,documentation库的Utils具有randomFrom(Iterable iterable)方法,该方法将采用Collection并从中返回一个随机元素< / p>

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

它位于Maven Central Repository:

<select multiple>

答案 6 :(得分:0)

使用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);
}

如果您还想处理空集合,则可以使用method with defaultValueIterables.get(from, i, null)

答案 7 :(得分:0)

可以将 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"));
}

答案 8 :(得分:-4)

用户Collections.shuffle(list);。然后你就可以得到第一个元素。这将是随机的。

或者您也可以这样做

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