2008-09-24 12 views
146

से एक यादृच्छिक तत्व चुनना मैं एक सेट से यादृच्छिक तत्व कैसे चुनूं? मैं जावा में हैशसेट या लिंक्ड हैशसेट से यादृच्छिक तत्व चुनने में विशेष रूप से रूचि रखता हूं। अन्य भाषाओं के लिए समाधान भी स्वागत है।सेट

+3

आपको यह देखने के लिए कुछ स्थितियों को निर्दिष्ट करना चाहिए कि यह वास्तव में आप क्या चाहते हैं। - आप यादृच्छिक तत्व का चयन कैसे कर सकते हैं? - क्या डेटा को हैशसेट या लिंक्ड हैशसेट में संग्रहीत करने की आवश्यकता है, न तो यादृच्छिक रूप से पहुंच योग्य नहीं है। - हैश सेट बड़ा है? क्या चाबियाँ छोटी हैं? –

उत्तर

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

यदि MyHashSet बड़ा है, तो यह औसत से धीमा समाधान होगा, (n/2) यादृच्छिक वस्तु को खोजने के लिए पुनरावृत्तियों की आवश्यकता होगी। – daniel

+5

यदि आपका डेटा हैश सेट में है, तो आपको O (n) समय चाहिए। यदि आप केवल एक तत्व चुन रहे हैं और डेटा हैशसेट में संग्रहीत है तो इसके चारों ओर कोई रास्ता नहीं है। –

+7

@ डेविड नेहेम: जावा में हैशसेट के विनिर्देशन में यह एक कमी है। सी ++ में, यह हैशसेट बनाने वाली बाल्टी तक सीधे पहुंचने में सक्षम होना सामान्य है, जो हमें यादृच्छिक तत्वों को अधिक कुशलतापूर्वक चुनने की अनुमति देता है। यदि जावा में यादृच्छिक तत्व आवश्यक हैं, तो कस्टम हैश सेट को परिभाषित करना उचित हो सकता है जो उपयोगकर्ता को हुड के नीचे देखने की अनुमति देता है। इसमें [बूस्ट के दस्तावेज़] [1] देखें। [1] http://www.boost.org/doc/libs/1_43_0/doc/html/unordered/buckets.html –

0

जब से तुम ने कहा, "अन्य भाषाओं के लिए समाधान का भी स्वागत है", यहां अजगर के लिए संस्करण है:

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

केवल, [1,2,3,4,5,6] एक सेट नहीं है, लेकिन एक सूची है, क्योंकि यह तेजी से लुकअप जैसी चीज़ों का समर्थन नहीं करती है। –

+0

आप अभी भी कर सकते हैं: >>> random.choice (सूची (सेट (रेंज (5))) >>> 4 आदर्श नहीं है लेकिन अगर आपको पूरी तरह से आवश्यकता है तो यह होगा। – SapphireSun

8

जावा में:

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

आपका उत्तर काम करता है, लेकिन set.toArray() भाग के कारण यह बहुत प्रभावी नहीं है। –

+12

आपको लूप के बाहर टूएरे को ले जाना चाहिए। –

2

कर सकते हैं केवल आपके नहीं सेट/सरणी का आकार/लंबाई प्राप्त करें, 0 और आकार/लंबाई के बीच यादृच्छिक संख्या उत्पन्न करें, फिर उस तत्व को कॉल करें जिसका सूचकांक उस नंबर से मेल खाता है? हैशसेट में एक .size() विधि है, मुझे पूरा यकीन है।

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

Mersenne ट्विस्टर कार्यों में बेहतर हैं लेकिन वहाँ PHP में array_rand का कोई मीट्रिक टन के बराबर है: -

psuedocode में

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

यह केवल तभी काम करता है जब प्रश्न में कंटेनर यादृच्छिक अनुक्रमणिका लुकअप का समर्थन करता है। कई कंटेनर कार्यान्वयन नहीं करते हैं (उदा।, हैश टेबल, बाइनरी पेड़, लिंक्ड सूचियां)। –

1

पीएचपी, यह मानते हुए "सेट" एक सरणी है।

0

पीएचपी, मीट्रिक टन का उपयोग कर:

$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

जावास्क्रिप्ट समाधान;)

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

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

या वैकल्पिक रूप से:

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

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

मैं दूसरा विकल्प पसंद करता हूं। :-) – marcospereira

+0

ओह, मुझे नई सरणी विधि जोड़ने का विस्तार करना पसंद है! –

70

एक कुछ हद तक संबंधित था क्या तुम जानते:

रहे हैंमें उपयोगी तरीकेपूरे संग्रह को शफल करने के लिए: Collections.shuffle(List<?>) और Collections.shuffle(List<?> list, Random rnd)

+0

बहुत बढ़िया! यह जावा दस्तावेज़ में कहीं भी क्रॉस रेफरेंस नहीं है! [पायथन की यादृच्छिक। शफल()] (http://docs.python.org/library/random.html?highlight=random.shuffle#random.shuffle) – smci

+11

लेकिन यह केवल सूचियों के साथ काम करता है, यानी, संरचनाएं जिनमें एक है .get() फ़ंक्शन। – bourbaki4481472

+4

@ bourbaki4481472 बिल्कुल सही है। यह केवल उन सूचीओं के लिए काम करता है जो 'सूची' इंटरफ़ेस को विस्तारित करते हैं, न कि ओपी द्वारा चर्चा 'सेट' इंटरफ़ेस। – Thomas

2

पर्ल 5

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

यहाँ एक तरह से यह करने के लिए है।

1

Icon एक सेट के प्रकार और एक यादृच्छिक तत्व ऑपरेटर, एकल "?", तो अभिव्यक्ति

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

1 और 5 के बीच एक यादृच्छिक संख्या का उत्पादन करेगा है।

यादृच्छिक बीज जब एक कार्यक्रम चलाया जाता है 0 पर आरंभ नहीं हो जाता है, इसलिए प्रत्येक रन उपयोग randomize()

1

सी # में पर अलग अलग परिणाम प्राप्त होने की

 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

क्या डाउनवॉटर कृपया एक टिप्पणी छोड़ देगा। धन्यवाद। –

+0

ऐसा लगता है कि वे डाउनवॉटेड हैं क्योंकि क्रैपी जावा शब्दकोश (या जिसे लिंक्ड हैशसेट कहा जाता है, जो कुछ भी है) को "यादृच्छिक रूप से एक्सेस नहीं किया जा सकता" (जिसे कुंजी द्वारा एक्सेस किया जा रहा है, मुझे लगता है)। जावा बकवास मुझे इतना हंसता है –

1

में तुतलाना

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

यह केवल सूचियों के लिए काम करता है, है ना? 'ईएलटी 'के साथ यह किसी भी अनुक्रम के लिए काम कर सकता है। – Ken

15

यदि आप जावा में ऐसा करना चाहते हैं, तो आपको तत्वों को किसी प्रकार के यादृच्छिक-अभिगम संग्रह (जैसे एक ArrayList) में कॉपी करने पर विचार करना चाहिए)। चूंकि, जब तक आपका सेट छोटा न हो, चयनित तत्व तक पहुंच महंगा हो (ओ (एन) के बजाय ओ (एन))। [ed: सूची प्रति भी ओ (एन)]

वैकल्पिक रूप से, आप एक और सेट कार्यान्वयन की तलाश कर सकते हैं जो आपकी आवश्यकताओं से अधिक निकटता से मेल खाता है। कॉमन्स संग्रह से ListOrderedSet आशाजनक लग रहा है।

+7

किसी सूची में कॉपी करने के लिए समय में ओ (एन) खर्च होगा और ओ (एन) मेमोरी का भी उपयोग करेगा, तो यह सीधे मानचित्र से लाने से बेहतर विकल्प क्यों होगा? – mdma

+10

यह इस बात पर निर्भर करता है कि आप सेट से कितनी बार चुनना चाहते हैं। प्रतिलिपि एक बार ऑपरेशन है और फिर आप सेट से जितनी बार चाहें उतनी बार चुन सकते हैं। यदि आप केवल एक तत्व चुन रहे हैं, तो हाँ प्रतिलिपि चीजों को तेज़ी से नहीं बनाती है। –

+0

@DanDyer, उत्कृष्ट उत्तर! – Thomas

3

Clojure समाधान:

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

यह समाधान भी रैखिक है, क्योंकि 'nth' तत्व प्राप्त करने के लिए आपको' seq' को भी पार करना होगा। –

+1

यह रैखिक भी है क्योंकि यह एक पंक्ति में अच्छी तरह से फिट बैठता है: डी –

1

दुर्भाग्य से, यह कुशलतापूर्वक स्टैंडर्ड लाइब्रेरी में से किसी में नहीं किया जा सकता (बेहतर हे (एन) की तुलना में) कंटेनर की स्थापना की।

यह अजीब है, क्योंकि हैश सेट के साथ-साथ बाइनरी सेट में यादृच्छिक पिक फ़ंक्शन जोड़ना बहुत आसान है। हैश सेट को स्पैस करने के लिए, आप हिट होने तक यादृच्छिक प्रविष्टियों को आजमा सकते हैं। एक बाइनरी पेड़ के लिए, आप अधिकतम ओ (लॉग 2) चरणों के साथ बाएं या दाएं उपट्री के बीच यादृच्छिक रूप से चुन सकते हैं। मैं नीचे बाद में का एक डेमो को क्रियान्वित किया है:

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 

मुझे मिल गया [995, 975, 971, 995, 1057, 1004, 966, 1052, 984, 1001] आउटपुट के रूप में है, तो वितरण तेजी अच्छा।

मैंने अपने लिए एक ही समस्या के साथ संघर्ष किया है, और मैंने अभी तक फैसला नहीं किया है कि इस अधिक कुशल पिक के प्रदर्शन लाभ को एक पायथन आधारित संग्रह का उपयोग करने के ऊपरी हिस्से के लायक है। मैं निश्चित रूप से इसे परिष्कृत कर सकता हूं और इसे सी में अनुवाद कर सकता हूं, लेकिन आज मेरे लिए यह बहुत अधिक काम है :)

+0

एक कारण मुझे लगता है कि यह एक बाइनरी पेड़ में लागू नहीं किया गया है कि ऐसी विधि वस्तुओं को समान रूप से नहीं लेती है। चूंकि उनके बाएं/दाएं बच्चों के बिना नोड्स हैं, इसलिए एक स्थिति हो सकती है जहां बाएं बच्चे में सही बच्चे (या इसके विपरीत) की तुलना में अधिक वस्तुएं होती हैं, इससे दाएं (या बाएं) बच्चे को एक आइटम चुनना होगा, और अधिक संभावना है। –

+0

@CommuSoft: यही कारण है कि मैं प्रत्येक subtree के आकार को स्टोर, इसलिए मैं उन पर आधारित मेरी संभावनाओं का चयन कर सकते हैं। –

2

सी ++। यह उचित रूप से त्वरित होना चाहिए, क्योंकि इसे पूरे सेट पर पुनरावृत्ति की आवश्यकता नहीं है, या इसे सॉर्ट करना आवश्यक नहीं है। यह सबसे आधुनिक कंपाइलर्स के साथ बॉक्स से बाहर काम करना चाहिए, मानते हैं कि वे tr1 का समर्थन करते हैं। यदि नहीं, तो आपको बूस्ट का उपयोग करने की आवश्यकता हो सकती है।

Boost docs यह समझाने के लिए यहां सहायक हैं, भले ही आप बूस्ट का उपयोग न करें।

चाल इस तथ्य का उपयोग करना है कि डेटा बाल्टी में बांटा गया है, और जल्दी से यादृच्छिक रूप से चुनी गई बाल्टी (उपयुक्त संभावना के साथ) की पहचान करने के लिए है।

//#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

इस सूत्र को पढ़ने के बाद, सबसे अच्छा मैं लिख सकता है:

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

सवाल सेट के बारे में पूछ रहा है, सरणी नहीं। वर्तमान समय के साथ 'रैंडम' बीज की कोई आवश्यकता नहीं है; 'नया रैंडम()' बॉक्स से ठीक से बीजित उदाहरण देता है। – dimo414

25

जावा के लिए तेजी से समाधान एक ArrayList और एक HashMap का उपयोग कर: [तत्व -> सूचकांक]।

प्रेरणा: मुझे RandomAccess गुणों के साथ आइटमों का एक सेट चाहिए, विशेष रूप से सेट से यादृच्छिक आइटम चुनने के लिए (pollRandom विधि देखें)। एक बाइनरी पेड़ में यादृच्छिक नेविगेशन सटीक नहीं है: पेड़ पूरी तरह से संतुलित नहीं होते हैं, जो एक समान वितरण के लिए नेतृत्व नहीं करेंगे।

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

धागे में सबसे अच्छा समाधान। Kudos :) –

+0

ठीक है कि काम करेगा लेकिन सवाल सेट इंटरफ़ेस के बारे में था। यह समाधान उपयोगकर्ताओं को रैंडमसेट के ठोस प्रकार संदर्भों को मजबूर करता है। –

+0

मुझे वास्तव में यह समाधान पसंद है, लेकिन यह धागा सुरक्षित नहीं है, मानचित्र और सूची के बीच त्रुटिपूर्णताएं हो सकती हैं, इसलिए मैं कुछ सिंक्रनाइज़ किए गए ब्लॉक –

1

मेथेमेटिका में:

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

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

या, हाल के संस्करणों में, बस:

RandomChoice[a] 

यह एक नीचे मत प्राप्त शायद इसलिए क्योंकि यह स्पष्टीकरण शामिल नहीं है इसलिए यहां एक है:

Random[] 0 और 1 के बीच एक छद्म यादृच्छिक फ्लोट उत्पन्न करता है। यह सूची की लंबाई से गुणा किया जाता है और फिर छत समारोह का उपयोग अगले पूर्णांक तक करने के लिए किया जाता है। यह सूचकांक तब a से निकाला जाता है।

के बाद से हैश तालिका कार्यक्षमता अक्सर मेथेमेटिका में नियमों के साथ किया जाता है, और नियमों सूचियों में जमा हो जाती है, एक का उपयोग हो सकता है:

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

यह असामान्य रूप से अक्षम है। आपके ArrayList कन्स्ट्रक्टर आपूर्ति किए गए सेट पर .toArray() को कॉल करता है। ToArray (अधिकतर यदि सभी मानक संग्रह कार्यान्वयन नहीं होते हैं) पूरे संग्रह पर पुनरावृत्त होते हैं, जैसे सरणी भरती है। फिर आप सूची को घुमाते हैं, जो प्रत्येक तत्व को यादृच्छिक तत्व के साथ बदल देता है। आप बस एक यादृच्छिक तत्व पर सेट पर फिर से शुरू करने से बेहतर होगा। –

+0

लघु और प्यारा ....... भयानक –

1

कैसे के बारे में सिर्फ

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

मस्ती के लिए मैं अस्वीकृति नमूनाकरण के आधार पर एक RandomHashSet लिखा था। यह थोड़ा हैकी है, क्योंकि हैश मैप हमें सीधे इसकी तालिका तक पहुंचने नहीं देता है, लेकिन इसे ठीक काम करना चाहिए।

यह किसी भी अतिरिक्त मेमोरी का उपयोग नहीं करता है, और लुकअप समय ओ (1) amortized है। (क्योंकि जावा हैशटेबल घना है)।

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

बिल्कुल मैं क्या सोच रहा था! सबसे बढ़िया उत्तर! – momomo

+0

वास्तव में, इसे वापस आना, मुझे लगता है कि यह काफी समान नहीं है, अगर हैशपैप में कई टकराव हैं और हम कई प्रश्न पूछते हैं। ऐसा इसलिए है क्योंकि जावा हैशप बाल्टी/चेनिंग का उपयोग करता है और यह कोड हमेशा विशेष बाल्टी में पहला तत्व लौटाएगा। हालांकि हम अभी भी हैश फ़ंक्शन की यादृच्छिकता पर समान हैं। –

14

इस से भी तेज है के लिए-प्रत्येक स्वीकार किए जाते हैं जवाब में पाश:

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

के लिए-प्रत्येक निर्माण कॉल हर पाश पर Iterator.hasNext(), लेकिन index < set.size() के बाद से, कि चेक अनावश्यक भूमि के ऊपर है। मैंने गति में 10-20% की वृद्धि देखी, लेकिन वाईएमएमवी। (इसके अलावा, यह अतिरिक्त रिटर्न स्टेटमेंट जोड़ने के बिना संकलित करता है।)

ध्यान दें कि यह कोड (और अधिकांश अन्य उत्तरों) किसी भी संग्रह पर लागू नहीं किया जा सकता है, न केवल सेट करें। सामान्य विधि के रूप में:

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

ग्रेट फ़ंक्शन, अब इसका उपयोग कर रहा है :) – akohout

0

आप भी यह शायद छोटे पैमाने पर काम करेंगे सरणी उपयोग सरणी को सेट मैं देख हस्तांतरण कर सकते हैं सबसे मतदान जवाब में पाश के लिए हे (एन) वैसे भी

Object[] arr = set.toArray(); 

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

यह स्वीकार्य उत्तर (खोथ) के समान है, लेकिन अनावश्यक size और i चर के साथ हटा दिया गया है।

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

दो aforementioned चर के साथ दूर कर रही है हालांकि, इसके बाद के संस्करण समाधान अभी भी बनी हुई है क्योंकि हम यादृच्छिक यादृच्छिक पर भरोसा कर रहे हैं (यादृच्छिक रूप से चयनित सूचकांक से शुरु करके) प्रत्येक यात्रा से अधिक 0 की ओर ही घटती है।

2

उपरोक्त समाधान विलंबता के मामले में बोलते हैं लेकिन प्रत्येक इंडेक्स का चयन होने की समान संभावना की गारंटी नहीं देता है।
यदि इसे माना जाना चाहिए, तो जलाशय नमूनाकरण का प्रयास करें।http://en.wikipedia.org/wiki/Reservoir_sampling
संग्रह। शफल() (जैसा कि कुछ द्वारा सुझाया गया है) एक ऐसे एल्गोरिदम का उपयोग करता है।

0

यदि आप वास्तव में यादृच्छिकता पर किसी भी गारंटी के बिना Set से "कोई भी" ऑब्जेक्ट चुनना चाहते हैं, तो सबसे पहले इसे इटरेटर द्वारा लौटाया जा सकता है।

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

हालांकि यह यादृच्छिक चयन नहीं होगा। एक ही सेट पर एक ही ऑपरेशन को कई बार प्रदर्शित करने की कल्पना करें। मुझे लगता है कि आदेश वही होगा। –

0

जावा 8 के साथ सबसे आसान है:

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

जहां n एक यादृच्छिक पूर्णांक है। बेशक यह for(elem: Col)

0

के साथ कम प्रदर्शन का है जो खोथ के उत्तर का उपयोग शुरुआती बिंदु के रूप में करते हुए एक सामान्य समाधान है।

/** 
* @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

यदि सेट आकार बड़ा नहीं है तो Arrays का उपयोग करके यह किया जा सकता है।

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

Guava के साथ हम एक छोटे से 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

बस इस यहाँ छोड़ना चाहते हैं:

random.choice(your_set) 

साँप कोई आपत्ति नहीं है।

0

आप एक 3 पार्टी पुस्तकालय कोई आपत्ति नहीं है, Utils पुस्तकालय एक IterableUtils एक randomFrom (Iterable iterable) विधि है कि एक सेट लेने के लिए और से यह

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

यह एक यादृच्छिक तत्व वापस आ जाएगी है कि है मेवेन सेंट्रल रिपोजिटरी में है:

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