2008-09-24 72 views
146

Làm cách nào để chọn một phần tử ngẫu nhiên từ một tập hợp? Tôi đặc biệt quan tâm đến việc chọn một phần tử ngẫu nhiên từ một số HashSet hoặc LinkedHashSet, trong Java. Các giải pháp cho các ngôn ngữ khác cũng được hoan nghênh.Chọn một phần tử ngẫu nhiên từ một tập hợp

+3

Bạn nên chỉ định một số điều kiện để xem đây có thực sự là điều bạn muốn hay không. - Bạn có thể chọn một phần tử ngẫu nhiên trong bao lâu? - Có phải dữ liệu cần được lưu trữ trong một HashSet hoặc LinkedHashSet, không phải là không thể truy cập ngẫu nhiên. - Bộ băm có lớn không? Các phím có nhỏ không? –

Trả lời

73
int size = myHashSet.size(); 
int item = new Random().nextInt(size); // In real life, the Random object should be rather more shared than this 
int i = 0; 
for(Object obj : myhashSet) 
{ 
    if (i == item) 
     return obj; 
    i++; 
} 
+71

Nếu myHashSet lớn, thì đây sẽ là một giải pháp khá chậm vì trung bình, (n/2) lặp lại sẽ cần thiết để tìm đối tượng ngẫu nhiên. – daniel

+5

nếu dữ liệu của bạn nằm trong tập hợp băm, bạn cần thời gian O (n). Không có cách nào xung quanh nó nếu bạn chỉ chọn một phần tử duy nhất và dữ liệu được lưu trữ trong một HashSet. –

+7

@ David Nehme: Đây là một nhược điểm trong đặc tả của HashSet trong Java. Trong C++, điển hình là có thể truy cập trực tiếp vào các nhóm tạo nên hashset, cho phép chúng ta chọn một phần tử ngẫu nhiên hiệu quả hơn. Nếu các phần tử ngẫu nhiên là cần thiết trong Java, có thể đáng giá để xác định một bộ băm tùy chỉnh cho phép người dùng nhìn dưới mui xe. Xem [tài liệu của boost] [1] để biết thêm một chút về điều này. [1] http://www.boost.org/doc/libs/1_43_0/doc/html/unordered/buckets.html –

0

Vì bạn nói: "Giải pháp cho các ngôn ngữ khác cũng được hoan nghênh", đây là phiên bản dành cho Python:

>>> import random 
>>> random.choice([1,2,3,4,5,6]) 
3 
>>> random.choice([1,2,3,4,5,6]) 
4 
+2

Chỉ, [1,2,3,4,5,6] không phải là một bộ, mà là một danh sách, vì nó không hỗ trợ những thứ như tra cứu nhanh. –

+0

Bạn vẫn có thể làm: >>> random.choice (danh sách (bộ (khoảng (5)))) >>> 4 Không lý tưởng nhưng nó sẽ làm nếu bạn hoàn toàn cần. – SapphireSun

8

Trong Java:

Set<Integer> set = new LinkedHashSet<Integer>(3); 
set.add(1); 
set.add(2); 
set.add(3); 

Random rand = new Random(System.currentTimeMillis()); 
int[] setArray = (int[]) set.toArray(); 
for (int i = 0; i < 10; ++i) { 
    System.out.println(setArray[rand.nextInt(set.size())]); 
} 
+10

Câu trả lời của bạn hoạt động, nhưng nó không phải là rất hiệu quả vì phần set.toArray(). –

+12

bạn nên di chuyển toArray ra bên ngoài vòng lặp. –

2

Có thể bạn không chỉ lấy kích thước/chiều dài của tập hợp/mảng, tạo ra một số ngẫu nhiên giữa 0 và kích thước/chiều dài, sau đó gọi phần tử có chỉ mục khớp với số đó? HashSet có một phương thức .size(), tôi khá chắc chắn.

Trong psuedocode -

function randFromSet(target){ 
var targetLength:uint = target.length() 
var randomIndex:uint = random(0,targetLength); 
return target[randomIndex]; 
} 
+0

Điều này chỉ hoạt động nếu vùng chứa được đề cập hỗ trợ tra cứu chỉ mục ngẫu nhiên. Nhiều triển khai vùng chứa không (ví dụ: bảng băm, cây nhị phân, danh sách được liên kết). –

1

PHP, giả sử "set" là một mảng:

$foo = array("alpha", "bravo", "charlie"); 
$index = array_rand($foo); 
$val = $foo[$index]; 

Các chức năng Mersenne Twister là tốt hơn nhưng không có MT tương đương với array_rand trong PHP.

0

PHP, sử dụng MT:

$items_array = array("alpha", "bravo", "charlie"); 
$last_pos = count($items_array) - 1; 
$random_pos = mt_rand(0, $last_pos); 
$random_item = $items_array[$random_pos]; 
1

giải pháp Javascript;)

function choose (set) { 
    return set[Math.floor(Math.random() * set.length)]; 
} 

var set = [1, 2, 3, 4], rand = choose (set); 

Hoặc cách khác:

Array.prototype.choose = function() { 
    return this[Math.floor(Math.random() * this.length)]; 
}; 

[1, 2, 3, 4].choose(); 
+0

Tôi thích phương án thứ hai. :-) – marcospereira

+0

ooh, tôi thích mở rộng thêm phương thức mảng mới! –

70

Một phần nào liên quan Bạn có biết:

Có phương pháp hữu ích trong java.util.Collections để xáo trộn toàn bộ bộ sưu tập: Collections.shuffle(List<?>)Collections.shuffle(List<?> list, Random rnd).

+0

Tuyệt vời! Đây không phải là bất kỳ nơi nào trong tài liệu java! Giống như [Python's random.shuffle()] (http://docs.python.org/library/random.html?highlight=random.shuffle#random.shuffle) – smci

+11

Nhưng điều này chỉ hoạt động với Danh sách, tức là, các cấu trúc có Hàm .get(). – bourbaki4481472

+4

@ bourbaki4481472 là hoàn toàn chính xác. Điều này chỉ làm việc cho những bộ sưu tập mở rộng giao diện 'List', không phải giao diện' Set' được thảo luận bởi OP. – Thomas

2

Perl 5

@hash_keys = (keys %hash); 
$rand = int(rand(@hash_keys)); 
print $hash{$hash_keys[$rand]}; 

Dưới đây là một cách để làm điều đó.

1

Icon có một kiểu thiết lập và điều hành một phần tử ngẫu nhiên, nhất nguyên "?", Vì vậy biểu thức

? set([1, 2, 3, 4, 5]) 

sẽ tạo ra một số ngẫu nhiên từ 1 đến 5.

Hạt giống ngẫu nhiên được khởi tạo 0 khi một chương trình được chạy, vì vậy tạo ra kết quả khác nhau trên mỗi lần sử dụng chạy randomize()

1

Trong C#

 Random random = new Random((int)DateTime.Now.Ticks); 

     OrderedDictionary od = new OrderedDictionary(); 

     od.Add("abc", 1); 
     od.Add("def", 2); 
     od.Add("ghi", 3); 
     od.Add("jkl", 4); 


     int randomIndex = random.Next(od.Count); 

     Console.WriteLine(od[randomIndex]); 

     // Can access via index or key value: 
     Console.WriteLine(od[1]); 
     Console.WriteLine(od["def"]); 
+0

Trình gỡ xuống có vui lòng để lại nhận xét hay không. Cảm ơn. –

+0

trông giống như chúng bị bỏ qua vì từ điển java crappy (hoặc được gọi là LinkedHashSet, bất kể địa ngục nào) không thể "truy cập ngẫu nhiên" (được truy cập bằng khóa, tôi đoán). Các crap java làm cho tôi cười rất nhiều –

1

Trong lisp

(defun pick-random (set) 
     (nth (random (length set)) set)) 
+0

Điều này chỉ hoạt động cho các danh sách, phải không? Với 'ELT', nó có thể hoạt động cho bất kỳ chuỗi nào. – Ken

15

Nếu bạn muốn làm điều đó trong Java, bạn nên xem xét sao chép các phần tử vào một số loại bộ sưu tập truy cập ngẫu nhiên (chẳng hạn như một ArrayList). Bởi vì, trừ khi thiết lập của bạn là nhỏ, truy cập vào phần tử đã chọn sẽ tốn kém (O (n) thay vì O (1)). [ed: bản sao danh sách cũng là O (n)]

Ngoài ra, bạn có thể tìm một triển khai Bộ khác phù hợp hơn với yêu cầu của bạn. ListOrderedSet từ Bộ sưu tập của Commons trông đầy hứa hẹn.

+7

Việc sao chép vào danh sách sẽ tốn O (n) trong thời gian và cũng sử dụng bộ nhớ O (n), vậy tại sao đó lại là lựa chọn tốt hơn so với tìm nạp trực tiếp từ bản đồ? – mdma

+10

Tùy thuộc vào số lần bạn muốn chọn từ bộ này. Bản sao là thao tác một lần và sau đó bạn có thể chọn từ tập hợp nhiều lần tùy ý. Nếu bạn chỉ chọn một phần tử, thì có bản sao không làm mọi thứ nhanh hơn. –

+0

@DanDyer, câu trả lời tuyệt vời! – Thomas

3

Clojure giải pháp:

(defn pick-random [set] (let [sq (seq set)] (nth sq (rand-int (count sq))))) 
+0

Giải pháp này cũng là tuyến tính, bởi vì để lấy phần tử 'nnth', bạn cũng phải đi qua' seq'. –

+1

Đó là tuyến tính cũng giống như nó vừa với nhau trong một dòng: D –

1

Thật không may, điều này không thể được thực hiện một cách hiệu quả (tốt hơn so với O (n)) trong bất kỳ bộ thư viện chuẩn thiết container.

Điều này thật kỳ quặc, vì việc thêm hàm chọn ngẫu nhiên vào bộ băm cũng như tập hợp nhị phân rất dễ dàng. Trong một bộ băm không thưa thớt, bạn có thể thử các mục nhập ngẫu nhiên, cho đến khi bạn nhận được một lần truy cập. Đối với cây nhị phân, bạn có thể chọn ngẫu nhiên giữa cây con trái hoặc phải, với tối đa các bước O (log2). Tôi đã thực hiện một bản demo của sau này dưới đây:

import random 

class Node: 
    def __init__(self, object): 
     self.object = object 
     self.value = hash(object) 
     self.size = 1 
     self.a = self.b = None 

class RandomSet: 
    def __init__(self): 
     self.top = None 

    def add(self, object): 
     """ Add any hashable object to the set. 
      Notice: In this simple implementation you shouldn't add two 
        identical items. """ 
     new = Node(object) 
     if not self.top: self.top = new 
     else: self._recursiveAdd(self.top, new) 
    def _recursiveAdd(self, top, new): 
     top.size += 1 
     if new.value < top.value: 
      if not top.a: top.a = new 
      else: self._recursiveAdd(top.a, new) 
     else: 
      if not top.b: top.b = new 
      else: self._recursiveAdd(top.b, new) 

    def pickRandom(self): 
     """ Pick a random item in O(log2) time. 
      Does a maximum of O(log2) calls to random as well. """ 
     return self._recursivePickRandom(self.top) 
    def _recursivePickRandom(self, top): 
     r = random.randrange(top.size) 
     if r == 0: return top.object 
     elif top.a and r <= top.a.size: return self._recursivePickRandom(top.a) 
     return self._recursivePickRandom(top.b) 

if __name__ == '__main__': 
    s = RandomSet() 
    for i in [5,3,7,1,4,6,9,2,8,0]: 
     s.add(i) 

    dists = [0]*10 
    for i in xrange(10000): 
     dists[s.pickRandom()] += 1 
    print dists 

tôi [995, 975, 971, 995, 1057, 1004, 966, 1052, 984, 1001] là đầu ra, vì vậy vỉa phân phối tốt.

Tôi đã vật lộn với cùng một vấn đề cho bản thân mình, và tôi vẫn chưa quyết định thời tiết hiệu suất đạt được của lựa chọn này hiệu quả hơn là giá trị trên không của việc sử dụng một bộ sưu tập dựa trên python. Tất nhiên tôi có thể tinh chỉnh nó và dịch nó sang C, nhưng đó là quá nhiều công việc cho tôi hôm nay :)

+0

Lý do tôi nghĩ rằng điều này không được thực hiện trong cây nhị phân là phương pháp như vậy sẽ không chọn các mục thống nhất. Vì chúng là các nút không có con trái/phải, một tình huống có thể xảy ra khi con trái chứa nhiều mục hơn con đúng (hoặc ngược lại), điều này sẽ làm cho việc chọn một mục ở bên phải (hoặc trái), càng có thể xảy ra. –

+0

@CommuSoft: Đó là lý do tại sao tôi lưu trữ kích thước của mỗi cây con, vì vậy tôi có thể chọn xác suất dựa trên những điều đó. –

2

C++. Điều này nên được hợp lý nhanh chóng, vì nó không yêu cầu lặp lại trên toàn bộ thiết lập, hoặc phân loại nó. Điều này sẽ làm việc ra khỏi hộp với các trình biên dịch hiện đại nhất, giả sử chúng hỗ trợ tr1. Nếu không, bạn có thể cần phải sử dụng Boost.

Boost docs hữu ích ở đây để giải thích điều này, ngay cả khi bạn không sử dụng Boost.

Bí quyết là sử dụng dữ liệu đã được chia thành các nhóm và để nhanh chóng xác định một nhóm được chọn ngẫu nhiên (với xác suất thích hợp).

//#include <boost/unordered_set.hpp> 
//using namespace boost; 
#include <tr1/unordered_set> 
using namespace std::tr1; 
#include <iostream> 
#include <stdlib.h> 
#include <assert.h> 
using namespace std; 

int main() { 
    unordered_set<int> u; 
    u.max_load_factor(40); 
    for (int i=0; i<40; i++) { 
    u.insert(i); 
    cout << ' ' << i; 
    } 
    cout << endl; 
    cout << "Number of buckets: " << u.bucket_count() << endl; 

    for(size_t b=0; b<u.bucket_count(); b++) 
    cout << "Bucket " << b << " has " << u.bucket_size(b) << " elements. " << endl; 

    for(size_t i=0; i<20; i++) { 
    size_t x = rand() % u.size(); 
    cout << "we'll quickly get the " << x << "th item in the unordered set. "; 
    size_t b; 
    for(b=0; b<u.bucket_count(); b++) { 
     if(x < u.bucket_size(b)) { 
     break; 
     } else 
     x -= u.bucket_size(b); 
    } 
    cout << "it'll be in the " << b << "th bucket at offset " << x << ". "; 
    unordered_set<int>::const_local_iterator l = u.begin(b); 
    while(x>0) { 
     l++; 
     assert(l!=u.end(b)); 
     x--; 
    } 
    cout << "random item is " << *l << ". "; 
    cout << endl; 
    } 
} 
-1

sau khi đọc chủ đề này, tốt nhất tôi có thể viết là:

static Random random = new Random(System.currentTimeMillis()); 
public static <T> T randomChoice(T[] choices) 
{ 
    int index = random.nextInt(choices.length); 
    return choices[index]; 
} 
+0

Câu hỏi đặt ra là hỏi về các bộ chứ không phải mảng. Cũng không cần phải gieo 'Random' với thời gian hiện tại; 'new Random()' trả về một thể hiện giống hệt nhau ra khỏi hộp. – dimo414

25

giải pháp nhanh cho Java sử dụng một ArrayListHashMap: [nguyên tố -> index].

Động lực: Tôi cần một tập hợp các mục có thuộc tính RandomAccess, đặc biệt là để chọn một mục ngẫu nhiên từ bộ này (xem phương pháp pollRandom). Điều hướng ngẫu nhiên trong cây nhị phân không chính xác: cây không được cân bằng hoàn hảo, điều này sẽ không dẫn đến sự phân bố đồng đều.

public class RandomSet<E> extends AbstractSet<E> { 

    List<E> dta = new ArrayList<E>(); 
    Map<E, Integer> idx = new HashMap<E, Integer>(); 

    public RandomSet() { 
    } 

    public RandomSet(Collection<E> items) { 
     for (E item : items) { 
      idx.put(item, dta.size()); 
      dta.add(item); 
     } 
    } 

    @Override 
    public boolean add(E item) { 
     if (idx.containsKey(item)) { 
      return false; 
     } 
     idx.put(item, dta.size()); 
     dta.add(item); 
     return true; 
    } 

    /** 
    * Override element at position <code>id</code> with last element. 
    * @param id 
    */ 
    public E removeAt(int id) { 
     if (id >= dta.size()) { 
      return null; 
     } 
     E res = dta.get(id); 
     idx.remove(res); 
     E last = dta.remove(dta.size() - 1); 
     // skip filling the hole if last is removed 
     if (id < dta.size()) { 
      idx.put(last, id); 
      dta.set(id, last); 
     } 
     return res; 
    } 

    @Override 
    public boolean remove(Object item) { 
     @SuppressWarnings(value = "element-type-mismatch") 
     Integer id = idx.get(item); 
     if (id == null) { 
      return false; 
     } 
     removeAt(id); 
     return true; 
    } 

    public E get(int i) { 
     return dta.get(i); 
    } 

    public E pollRandom(Random rnd) { 
     if (dta.isEmpty()) { 
      return null; 
     } 
     int id = rnd.nextInt(dta.size()); 
     return removeAt(id); 
    } 

    @Override 
    public int size() { 
     return dta.size(); 
    } 

    @Override 
    public Iterator<E> iterator() { 
     return dta.iterator(); 
    } 
} 
+2

Giải pháp tốt nhất trong chuỗi. Kudo :) –

+0

Điều đó sẽ hiệu quả nhưng câu hỏi là về giao diện Set. Giải pháp này buộc người dùng phải có các tham chiếu kiểu cụ thể của RandomSet. –

+0

Tôi thực sự thích giải pháp này, nhưng nó không phải là chủ đề an toàn, không chính xác giữa Bản đồ và Danh sách có thể xảy ra, vì vậy tôi sẽ thêm một số khối đồng bộ –

1

Trong Mathematica:

a = {1, 2, 3, 4, 5} 

a[[ ⌈ Length[a] Random[] ⌉ ]] 

Hoặc, trong các phiên bản gần đây, chỉ cần:

RandomChoice[a] 

này đã nhận được một xuống bỏ phiếu, có lẽ vì nó thiếu lời giải thích, vì vậy đây một là:

Random[] tạo ra một pseudorandom float giữa 0 và 1. Điều này được nhân với độ dài của danh sách và sau đó chức năng trần được sử dụng để làm tròn đến số nguyên tiếp theo. Chỉ số này sau đó được chiết xuất từ ​​a.

Kể từ khi chức năng bảng băm thường được thực hiện với quy tắc trong Mathematica, và các quy tắc được lưu trữ trong danh sách, người ta có thể sử dụng:

a = {"Badger" -> 5, "Bird" -> 1, "Fox" -> 3, "Frog" -> 2, "Wolf" -> 4}; 
6
List asList = new ArrayList(mySet); 
Collections.shuffle(asList); 
return asList.get(0); 
+12

Điều này rất không hiệu quả. Hàm tạo của ArrayList của bạn gọi .toArray() trên tập hợp được cung cấp. ToArray (trong hầu hết nếu không phải tất cả các triển khai bộ sưu tập tiêu chuẩn) lặp lại toàn bộ bộ sưu tập, điền vào một mảng khi nó đi. Sau đó, bạn trộn danh sách, hoán đổi từng phần tử với một phần tử ngẫu nhiên. Bạn sẽ được tốt hơn nhiều chỉ đơn giản là lặp qua các thiết lập để một yếu tố ngẫu nhiên. –

+0

Ngắn và ngọt ....... tuyệt vời –

1

Làm thế nào về chỉ

public static <A> A getRandomElement(Collection<A> c, Random r) { 
    return new ArrayList<A>(c).get(r.nextInt(c.size())); 
} 
0

Đối với niềm vui tôi đã viết một RandomHashSet dựa trên mẫu từ chối. Đó là một chút hacky, kể từ HashMap không cho phép chúng tôi truy cập vào bảng của nó trực tiếp, nhưng nó sẽ làm việc tốt.

Nó không sử dụng bất kỳ bộ nhớ bổ sung nào, và thời gian tra cứu là O (1) được khấu hao. (Bởi vì java HashTable là dày đặc).

class RandomHashSet<V> extends AbstractSet<V> { 
    private Map<Object,V> map = new HashMap<>(); 
    public boolean add(V v) { 
     return map.put(new WrapKey<V>(v),v) == null; 
    } 
    @Override 
    public Iterator<V> iterator() { 
     return new Iterator<V>() { 
      RandKey key = new RandKey(); 
      @Override public boolean hasNext() { 
       return true; 
      } 
      @Override public V next() { 
       while (true) { 
        key.next(); 
        V v = map.get(key); 
        if (v != null) 
         return v; 
       } 
      } 
      @Override public void remove() { 
       throw new NotImplementedException(); 
      } 
     }; 
    } 
    @Override 
    public int size() { 
     return map.size(); 
    } 
    static class WrapKey<V> { 
     private V v; 
     WrapKey(V v) { 
      this.v = v; 
     } 
     @Override public int hashCode() { 
      return v.hashCode(); 
     } 
     @Override public boolean equals(Object o) { 
      if (o instanceof RandKey) 
       return true; 
      return v.equals(o); 
     } 
    } 
    static class RandKey { 
     private Random rand = new Random(); 
     int key = rand.nextInt(); 
     public void next() { 
      key = rand.nextInt(); 
     } 
     @Override public int hashCode() { 
      return key; 
     } 
     @Override public boolean equals(Object o) { 
      return true; 
     } 
    } 
} 
+1

Chính xác những gì tôi đang nghĩ! Câu trả lời hay nhất! – momomo

+0

Trên thực tế, quay trở lại với nó, tôi đoán điều này là không hoàn toàn thống nhất, nếu hashmap có nhiều va chạm và chúng tôi làm nhiều truy vấn. Đó là bởi vì hashmap java sử dụng nhóm/chuỗi và mã này sẽ luôn trả về phần tử đầu tiên trong nhóm cụ thể. Chúng tôi vẫn thống nhất về tính ngẫu nhiên của hàm băm mặc dù. –

14

Đây là nhanh hơn so với for-each vòng lặp trong câu trả lời được chấp nhận:

int index = rand.nextInt(set.size()); 
Iterator<Object> iter = set.iterator(); 
for (int i = 0; i < index; i++) { 
    iter.next(); 
} 
return iter.next(); 

Các for-each cấu trúc gọi Iterator.hasNext() trên mỗi vòng lặp, nhưng kể từ khi index < set.size(), kiểm tra đó là chi phí không cần thiết. Tôi thấy tốc độ tăng 10-20%, nhưng YMMV. (Ngoài ra, điều này biên dịch mà không cần phải thêm câu trả lại bổ sung.)

Lưu ý rằng mã này (và hầu hết các câu trả lời khác) có thể được áp dụng cho bất kỳ Bộ sưu tập nào chứ không chỉ là Đặt. Trong form method generic:

public static <E> E choice(Collection<? extends E> coll, Random rand) { 
    if (coll.size() == 0) { 
     return null; // or throw IAE, if you prefer 
    } 

    int index = rand.nextInt(coll.size()); 
    if (coll instanceof List) { // optimization 
     return ((List<? extends E>) coll).get(index); 
    } else { 
     Iterator<? extends E> iter = coll.iterator(); 
     for (int i = 0; i < index; i++) { 
      iter.next(); 
     } 
     return iter.next(); 
    } 
} 
+0

Chức năng tuyệt vời, sử dụng nó ngay bây giờ :) – akohout

0

bạn cũng có thể chuyển các thiết lập để sử dụng mảng mảng nó có lẽ sẽ làm việc trên quy mô nhỏ tôi thấy các vòng lặp for trong câu trả lời đã bỏ phiếu nhất là O (n) anyway

Object[] arr = set.toArray(); 

int v = (int) arr[rnd.nextInt(arr.length)]; 
1

Điều này giống với câu trả lời được chấp nhận (Khoth), nhưng với các biến số sizei không cần thiết đã bị xóa.

int random = new Random().nextInt(myhashSet.size()); 
    for(Object obj : myhashSet) { 
     if (random-- == 0) { 
      return obj; 
     } 
    } 

Mặc dù với việc từ bỏ hai biến nói trên, giải pháp trên vẫn ngẫu nhiên vì chúng ta đang dựa vào ngẫu nhiên (bắt đầu từ một chỉ số được lựa chọn ngẫu nhiên) để giảm giá trị bản thân về phía 0 qua mỗi lần lặp.

2

Giải pháp ở trên nói về độ trễ nhưng không đảm bảo xác suất bằng nhau của từng chỉ mục được chọn.
Nếu cần được xem xét, hãy thử lấy mẫu hồ chứa.http://en.wikipedia.org/wiki/Reservoir_sampling.
Collections.shuffle() (như được đề xuất bởi một số ít) sử dụng một thuật toán như vậy.

0

Nếu bạn thực sự chỉ muốn chọn đối tượng "bất kỳ" từ Set, không có bất kỳ sự đảm bảo nào về tính ngẫu nhiên, cách dễ nhất là lấy đối tượng đầu tiên được trả về bởi trình lặp.

Set<Integer> s = ... 
    Iterator<Integer> it = s.iterator(); 
    if(it.hasNext()){ 
     Integer i = it.next(); 
     // i is a "random" object from set 
    } 
+1

Đây sẽ không phải là một lựa chọn ngẫu nhiên mặc dù. Hãy tưởng tượng thực hiện cùng một thao tác trên cùng một tập hợp nhiều lần. Tôi nghĩ rằng thứ tự sẽ giống nhau. –

0

Cách dễ dàng nhất với Java 8 là:

outbound.stream().skip(n % outbound.size()).findFirst().get() 

nơi n là một số nguyên ngẫu nhiên. Tất nhiên, hiệu suất của nó kém hiệu quả hơn với for(elem: Col)

0

Một giải pháp chung sử dụng câu trả lời của Khoth làm điểm bắt đầu.

/** 
* @param set a Set in which to look for a random element 
* @param <T> generic type of the Set elements 
* @return a random element in the Set or null if the set is empty 
*/ 
public <T> T randomElement(Set<T> set) { 
    int size = set.size(); 
    int item = random.nextInt(size); 
    int i = 0; 
    for (T obj : set) { 
     if (i == item) { 
      return obj; 
     } 
     i++; 
    } 
    return null; 
} 
0

Nếu kích thước thiết lập không lớn thì bằng cách sử dụng Mảng này có thể được thực hiện.

int random; 
HashSet someSet; 
<Type>[] randData; 
random = new Random(System.currentTimeMillis).nextInt(someSet.size()); 
randData = someSet.toArray(); 
<Type> sResult = randData[random]; 
0

Với Guava chúng ta có thể làm tốt hơn một chút so với câu trả lời của Khoth:

public static E random(Set<E> set) { 
    int index = random.nextInt(set.size(); 
    if (set instanceof ImmutableSet) { 
    // ImmutableSet.asList() is O(1), as is .get() on the returned list 
    return set.asList().get(index); 
    } 
    return Iterables.get(set, index); 
} 
0

Chỉ muốn để lại điều này ở đây:

random.choice(your_set) 

không nhớ con rắn.

0

Nếu bạn không nhớ một thư viện của bên thứ 3, thư viện UtilsIterableUtils rằng có một phương pháp randomFrom (Iterable iterable) rằng sẽ mất một Set và trả về một yếu tố ngẫu nhiên từ nó

Set<Object> set = new HashSet<>(); 
set.add(...); 
... 
Object random = IterableUtils.randomFrom(set); 

Nó nằm trong Kho lưu trữ trung tâm của Maven tại:

<dependency> 
    <groupId>com.github.rkumsher</groupId> 
    <artifactId>utils</artifactId> 
    <version>1.0</version> 
</dependency> 
Các vấn đề liên quan