2017-08-31 76 views

回答

7

爲什麼與流?你只需要從0得到一個隨機數,以列表的大小,然後在這個指標叫get

Random r = new Random(); 
ElementType e = list.get(r.nextInt(list.size()); 

流會給你這裏沒有什麼有趣的,但你可以嘗試:

Random r = new Random(); 
ElementType e = list.stream().skip(r.nextInt(list.size()-1).findFirst().get(); 

想法是跳過任意數量的元素(但不是最後一個!),然後獲取第一個元素(如果存在)。結果你將有一個Optional<ElementType這將是非空的,然後提取其值get。在跳過之後,您有很多選擇。

這裏使用流是非常低效的...

注意:這些解決方案都需要在考慮空單,但問題是在非空列表定義。

+0

它將如果列表產生一個NoSuchElementException是空的 – Andrew

+0

@AndrewTobilko好吧,但從空列表中提取一個隨機元素總是未定義的。同樣適合您的解決方案... –

+0

@ Jean-BaptisteYunés有道理,謝謝。 – aekber

3

如果HAVE使用流,我寫了一個優雅的,雖然非常低效的收集,沒有工作:

/** 
* Returns a random item from the stream (or null in case of an empty stream). 
* This operation can't be lazy and is inefficient, and therefore shouldn't 
* be used on streams with a large number or items or in performance critical sections. 
* @return a random item from the stream or null if the stream is empty. 
*/ 
public static <T> Collector<T, List<T>, T> randomItem() { 
    final Random RANDOM = new Random(); 
    return Collector.of(() -> (List<T>) new ArrayList<T>(), 
           (acc, elem) -> acc.add(elem), 
           (list1, list2) -> ListUtils.union(list1, list2), // Using a 3rd party for list union, could be done "purely" 
           list -> list.isEmpty() ? null : list.get(RANDOM.nextInt(list.size()))); 
} 

用法:

@Test 
public void standardRandomTest() { 
    assertThat(Stream.of(1, 2, 3, 4).collect(randomItem())).isBetween(1, 4); 
} 
相關問題