एक सेट से एक यादृच्छिक तत्व उठा रहा है


180

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


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

जवाबों:


88
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++;
}

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

6
यदि आपका डेटा हैश सेट में है, तो आपको O (n) समय चाहिए। अगर आप सिर्फ एक ही तत्व चुन रहे हैं तो इसके आसपास कोई रास्ता नहीं है और डेटा को किसी HashSet में संग्रहीत किया जाता है।
डेविड नेहमे सेप 25'08

8
@ डेविड नेहमे: यह जावा में हैशसेट के विनिर्देश में एक खामी है। सी ++ में, यह विशिष्ट है कि सीधे हैशसेट बनाने वाली बाल्टियों का उपयोग करने में सक्षम हो, जो हमें अधिक कुशलता से एक यादृच्छिक तत्वों का चयन करने की अनुमति देता है। यदि जावा में यादृच्छिक तत्व आवश्यक हैं, तो कस्टम हैश सेट को परिभाषित करना सार्थक हो सकता है जो उपयोगकर्ता को हुड के नीचे देखने की अनुमति देता है। इसमें कुछ और के लिए [बूस्ट के डॉक्स] [१] देखें। [१] बूस्ट.ओआरजी
हारून मैकडैड

11
यदि सेट को एकाधिक एक्सेस पर म्यूट नहीं किया गया है, तो आप इसे एक सरणी में कॉपी कर सकते हैं और फिर O (1) तक पहुंच सकते हैं। बस myHashSet.toArray ()
ykaganovich

2
@ykaganovich इस मामले को बदतर नहीं करेगा, क्योंकि सेट को नए सरणी में कॉपी करना होगा? docs.oracle.com/javase/7/docs/api/java/util/… "इस विधि को एक नया सरणी आवंटित करना होगा, भले ही यह संग्रह किसी सरणी द्वारा समर्थित हो"
anton1980

73

कुछ हद तक संबंधित क्या आप जानते हैं:

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


बहुत बढ़िया! यह जावा डॉक में कहीं भी पार नहीं है! जैसे पायथन का बेतरतीब।शफल ()
स्माइली

25
लेकिन यह केवल सूचियों के साथ काम करता है, अर्थात, संरचना जो एक .get () फ़ंक्शन है।
बुर्बकि4481472

4
@ bourbaki4481472 बिल्कुल सही है। यह केवल उन संग्रह के लिए काम करता है जो Listइंटरफ़ेस का विस्तार करते हैं , न Setकि ओपी द्वारा चर्चा किए गए इंटरफ़ेस का।
थॉमस

31

जावा का तेज़ समाधान ArrayLista 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();
    }
}

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

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

@KonstantinosChalkias अंतर्निहित संग्रह या तो थ्रेड सुरक्षित नहीं हैं। केवल नाम वाले Concurrentही वास्तव में सुरक्षित हैं, जो लपेटे हुए Collections.synchronized()हैं वे अर्ध-सुरक्षित हैं। साथ ही ओपी ने समसामयिकता के बारे में कुछ नहीं कहा, इसलिए यह एक मान्य और अच्छा जवाब है।
ट्वीस्ट्रीम

यहां लौटाए गए पुनरावृत्त तत्वों को तत्वों से निकालने में सक्षम नहीं होना चाहिए dta(यह Iterators.unmodifiableIteratorउदाहरण के लिए अमरूद के माध्यम से प्राप्त किया जा सकता है )। अन्यथा AbstractSet में हटाने और सभी को फिर से लागू करने के लिए डिफ़ॉल्ट और AbstractSet और उसके माता पिता के साथ काम कर रहे हैं कि यह आपके गड़बड़ कर देगा RandomSet!
muued

अच्छा समाधान है। आप वास्तव में एक पेड़ का उपयोग कर सकते हैं यदि प्रत्येक नोड में उप जड़ों में नोड्स की संख्या होती है। फिर 0..1 में एक यादृच्छिक वास्तविक गणना करें और नोड काउंट्स के आधार पर प्रत्येक नोड पर एक भारित 3-तरफा निर्णय (वर्तमान नोड का चयन करें या बाएं या दाएं उपशीर्षक में उतरें) करें। लेकिन अपने समाधान imo बहुत अच्छा है।
जीन

30

यह स्वीकृत उत्तर के लिए प्रत्येक लूप से अधिक तेज़ है:

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% की वृद्धि देखी, लेकिन YMMV। (इसके अलावा, यह अतिरिक्त रिटर्न स्टेटमेंट को जोड़ने के बिना संकलित करता है।)

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

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

15

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

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


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

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

यदि आप पुनरावृत्ति के साथ लेने में सक्षम होना चाहते हैं तो यह केवल एक बार का ऑपरेशन है। यदि आप चाहते हैं कि चुनी गई वस्तु को सेट से हटा दिया जाए, तो आप O (n) पर वापस आ जाएंगे।
शलजम एंथ्रॉपी


9

जावा में:

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

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

12
आपको लूप के बाहर तक ऐरे को ले जाना चाहिए।
डेविड नेहमे सेप

8
List asList = new ArrayList(mySet);
Collections.shuffle(asList);
return asList.get(0);

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

4

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

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

हालांकि उपरोक्त दोनों चर के साथ दूर करने के बावजूद, उपरोक्त समाधान अभी भी यादृच्छिक बना हुआ है क्योंकि हम 0प्रत्येक पुनरावृत्ति की ओर खुद को कम करने के लिए यादृच्छिक (एक यादृच्छिक रूप से चयनित सूचकांक पर शुरू) पर भरोसा कर रहे हैं ।


1
तीसरी लाइन भी हो सकती है if (--random < 0) {, जहाँ randomपहुँचता है -1
सल्वाडोर

3

लौंग का घोल:

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

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

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

2

पर्ल ५

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

यहाँ यह करने का एक तरीका है।


2

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

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

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

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

2

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


1

चूंकि आपने कहा "अन्य भाषाओं के लिए समाधान भी स्वागत योग्य हैं", यहाँ पायथन के लिए संस्करण है:

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

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

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

1

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

Psuedocode में -

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

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

1

PHP, "सेट" मानकर एक सरणी है:

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

Mersenne ट्विस्टर फ़ंक्शन बेहतर हैं, लेकिन PHP में array_rand के बराबर MT नहीं है।


अधिकांश सेट कार्यान्वयनों को एक (i) या अनुक्रमण ऑपरेटर नहीं मिलता है, इसलिए आईडी मानती है कि OP ने अपना सेट क्यों निर्दिष्ट किया
DownloadPizza

1

आइकन में एक सेट प्रकार और एक यादृच्छिक-तत्व ऑपरेटर है, एकात्मक "?", इसलिए अभिव्यक्ति

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

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

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


1

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"]);

ऐसा लगता है कि वे निराश हैं क्योंकि गंदे जावा शब्दकोश (या तथाकथित लिंक्डशैसेट, जो भी नरक है) को "बेतरतीब ढंग से एक्सेस" नहीं किया जा सकता है (जो कुंजी द्वारा पहुँचा जा रहा है, मुझे लगता है)। जावा बकवास मुझे बहुत
हँसाती है

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

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

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

1

लिस्प में

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

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

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


1

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

यह किसी भी अतिरिक्त मेमोरी का उपयोग नहीं करता है, और लुकअप समय O (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
मैं बिल्कुल यहीं सोच रहा था! सबसे बढ़िया उत्तर!
एमएमएम

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

1

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

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

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


1

अमरूद के साथ हम खोथ के जवाब से थोड़ा बेहतर कर सकते हैं:

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

PHP, 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];

0

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

Object[] arr = set.toArray();

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

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

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

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

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

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

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] मिला, इसलिए वितरण अच्छा हुआ।

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


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

1
@CommuSoft: यही कारण है कि मैं प्रत्येक उपशीर्षक के आकार को संग्रहीत करता हूं, इसलिए मैं उन पर आधारित अपनी संभावनाओं को चुन सकता हूं।
थॉमस अहले
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.