একটি সেট থেকে একটি এলোমেলো উপাদান বাছাই করা


180

আমি কীভাবে একটি সেট থেকে একটি এলোমেলো উপাদান চয়ন করব? আমি জাভাতে হ্যাশসেট বা লিংকডহ্যাশসেট থেকে এলোমেলো উপাদান বাছতে আগ্রহী। অন্যান্য ভাষার সমাধানও স্বাগত।


5
আপনি যা চান তা আসলে এটি কিনা আপনার কিছু শর্ত নির্দিষ্ট করতে হবে should - আপনি কীভাবে বারবার এলোমেলো উপাদান নির্বাচন করতে যাচ্ছেন? - ডেটা কি কোনও হ্যাশসেট বা লিংকডহ্যাশসেটে সংরক্ষণ করার দরকার আছে, এগুলি এলোমেলোভাবে অ্যাক্সেসযোগ্য নয়। - হ্যাশ কি বড় সেট? চাবি ছোট?
ডেভিড নেহমে

উত্তর:


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

93
যদি মাই হ্যাশসেটটি বড় হয়, তবে এটি গড় থেকে একটি ধীরে ধীরে সমাধান হবে, কারণ এলোমেলো বস্তুটি সন্ধানের জন্য (n / 2) পুনরাবৃত্তির প্রয়োজন হবে।
ড্যানিয়েল

6
যদি আপনার ডেটা হ্যাশ সেটে থাকে তবে আপনার ও (এন) সময় দরকার। এটির কোনও উপায় নেই যদি আপনি কেবল একটি একক উপাদান বাছাই করে থাকেন এবং ডেটা হ্যাশসেটে সঞ্চিত থাকে।
ডেভিড নেহমে

8
@ ডেভিড নেহমে: জাভায় হ্যাশসেটের নির্দিষ্টকরণের ক্ষেত্রে এটি একটি অপূর্ণতা। সি ++ তে, হ্যাশসেটটি তৈরি করা বালতিগুলি সরাসরি অ্যাক্সেস করতে সক্ষম হওয়াই সাধারণ, যা আমাদের আরও দক্ষতার সাথে একটি এলোমেলো উপাদান নির্বাচন করতে দেয়। যদি জাভাতে এলোমেলো উপাদানগুলি প্রয়োজনীয় হয় তবে এটি একটি কাস্টম হ্যাশ সেট সংজ্ঞায়িত করা উপযুক্ত হতে পারে যা ব্যবহারকারীকে ফণার নীচে দেখতে দেয়। এর মধ্যে আরও কিছুর জন্য [বুস্টের ডক্স] [1] দেখুন। [1] boost.org/doc/libs/1_43_0/doc/html/unordered/buckets.html
অ্যারন

11
যদি সেটটি একাধিক অ্যাক্সেসের মধ্যে রূপান্তরিত না করা হয় তবে আপনি এটিকে একটি অ্যারেতে অনুলিপি করতে পারেন এবং তারপরে ও (1) এ অ্যাক্সেস করতে পারেন। স্রেফ myHashSet.toArray () ব্যবহার করুন
ykaganovich

2
@ ইয়াকাগানোভিচ এটি কি আরও খারাপ করে দেবে না, যেহেতু সেটটি নতুন অ্যারেতে অনুলিপি করতে হবে? docs.oracle.com/javase/7/docs/api/java/util/… "এই সংগ্রহটি কোনও অ্যারে দ্বারা সমর্থিত হলেও এই পদ্ধতিটি অবশ্যই একটি নতুন অ্যারে বরাদ্দ করতে হবে"
anton1980

73

কিছুটা সম্পর্কিত আপনি কি জানতেন:

java.util.Collectionsপুরো সংগ্রহ বদলে দেওয়ার জন্য দরকারী পদ্ধতি রয়েছে : Collections.shuffle(List<?>)এবং Collections.shuffle(List<?> list, Random rnd)


অসাধারণ! এটি জাভা ডকের কোথাও ক্রসরেফারেন্সড নয়! ভালো লেগেছে পাইথন এর random.shuffle ()
smci

25
তবে এটি কেবল তালিকাগুলির সাথে কাজ করে ie
bourbaki4481472

4
@ bourbaki4481472 একেবারে সঠিক। এটি কেবল সেই সংগ্রহগুলির জন্য কাজ করে যা Listইন্টারফেসটি প্রসারিত করে , Setওপি দ্বারা আলোচিত ইন্টারফেসটি নয় ।
থমাস

31

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

ওয়েল যে কাজ করবে কিন্তু প্রশ্ন সেট ইন্টারফেস সম্পর্কে ছিল। এই সমাধানটি ব্যবহারকারীদের র‌্যান্ডমসেটের কংক্রিট ধরণের উল্লেখ করতে বাধ্য করে forces
জোহান টিডন

আমি এই সমাধানটি সত্যই পছন্দ করি, তবে এটি থ্রেড নিরাপদ নয়, মানচিত্র এবং তালিকার মধ্যে
অপ্রতুল্যতা

@ কনস্টান্টিনোস চ্যালকিয়াস অন্তর্নির্মিত সংগ্রহগুলি থ্রেডও নিরাপদ নয়। কেবল নামের সাথে কেবল Concurrentসত্যই নিরাপদ, মোড়কগুলি Collections.synchronized()আধা-নিরাপদ। এছাড়াও ওপি সমঝোতা সম্পর্কে কিছু বলেনি তাই এটি একটি বৈধ, এবং ভাল উত্তর।
TWiStErRob

এখানে ফিরে আসা পুনরাবৃত্তকারী উপাদানগুলি সরিয়ে ফেলতে সক্ষম হবে না dta( Iterators.unmodifiableIteratorউদাহরণস্বরূপ এটি পেয়ারা দিয়ে অর্জন করা যেতে পারে )। অন্যথায় যেমন অ্যাবস্ট্রাক্টসেটে সমস্ত অপসারণ এবং রক্ষণাবেক্ষণের ডিফল্ট বাস্তবায়ন এবং সেই পুনরাবৃত্তকারীর সাথে কাজ করা এর পিতামাতারা আপনার গোলমাল করবে RandomSet!
14

সুন্দর সমাধান। প্রতিটি নোডের শিকড়ের সাবট্রিতে নোডের সংখ্যা থাকলে আপনি আসলে একটি গাছ ব্যবহার করতে পারেন। তারপরে ০.১. এ এলোমেলো বাস্তবের গণনা করুন এবং নোডের গণনার উপর ভিত্তি করে প্রতিটি নোডে একটি ওজনযুক্ত 3-উপায় সিদ্ধান্ত নিন (বর্তমান নোড নির্বাচন করুন বা বাম বা ডান সাবট্রিতে নেমে আসা)। তবে ইমো আপনার সমাধানটি বেশ সুন্দর।
জেন

29

এটি গৃহীত উত্তরের প্রতিটি লুপের চেয়ে দ্রুত:

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

15

আপনি যদি জাভাতে এটি করতে চান তবে আপনার উপাদানগুলিকে একরকম এলোমেলো-অ্যাক্সেস সংগ্রহে (যেমন একটি অ্যারেলিস্ট) অনুলিপি করা উচিত। কারণ, আপনার সেটটি ছোট না হলে নির্বাচিত উপাদান অ্যাক্সেস করা ও (1) এর পরিবর্তে (O (n) ব্যয়বহুল হবে n [সম্পাদনা: তালিকার অনুলিপিও ও (এন)]

বিকল্পভাবে, আপনি অন্য সেট প্রয়োগের সন্ধান করতে পারেন যা আপনার প্রয়োজনীয়তার সাথে আরও ঘনিষ্ঠভাবে মেলে। ListOrderedSet কমন্স সংগ্রহ থেকে প্রতিশ্রুতি দেখায়।


8
একটি তালিকাতে অনুলিপি করতে ও (এন) সময় ব্যয় করতে হবে এবং ও (এন) মেমরিটিও ব্যবহার করবে, তবে কেন সরাসরি মানচিত্র থেকে আনার চেয়ে ভাল পছন্দ হবে?
এমডিএমএ

12
এটি সেট থেকে আপনি কতবার বাছাই করতে চান তার উপর নির্ভর করে। অনুলিপিটি ওয়ান টাইম অপারেশন এবং তারপরে আপনি সেট থেকে আপনার প্রয়োজনের তুলনায় অনেকবার বাছাই করতে পারেন। আপনি যদি কেবল একটি উপাদান বাছাই করেন তবে হ্যাঁ অনুলিপি জিনিসগুলিকে আরও দ্রুত করে না।
ড্যান ডায়ার

আপনি যদি পুনরাবৃত্তি দিয়ে বাছাই করতে সক্ষম হতে চান তবে এটি কেবলমাত্র এক সময়ের অপারেশন। আপনি যদি চান যে পছন্দ করা আইটেমটি সেট থেকে সরানো হবে, তবে আপনি আবার ও (এন) এ ফিরে আসবেন।
TurnipEntropy


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
আপনার উত্তরটি কাজ করে তবে সেট.টো অ্যারির () অংশের কারণে এটি খুব দক্ষ নয়।
ক্লু কম

12
আপনার অরেতে লুপের বাইরে চলে যাওয়া উচিত।
ডেভিড নেহমে

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

21
এটি অস্বাভাবিকভাবে অদক্ষ। আপনার অ্যারেলিস্ট কনস্ট্রাক্টর সরবরাহ করা সেটটিতে .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
এটি লিনিয়ার যেমন এটি একটি লাইনে ভাল ফিট করে: ডি
ক্রিজিসটফ ওলনি

2

পার্ল 5

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

এটি করার একটি উপায় এখানে।


2

সি ++। এটি যুক্তিসঙ্গতভাবে দ্রুত হওয়া উচিত কারণ এটি পুরো সেটটিতে পুনরাবৃত্তি বা বাছাইয়ের প্রয়োজন হয় না require এটি টিআর 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.wikedia.org/wiki/Reservoir_sampling
কালেকশন.শ্যাফল () কয়েকটি দ্বারা প্রস্তাবিত হিসাবে) এরকম একটি অ্যালগরিদম ব্যবহার করা হয়।


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] একটি সেট নয়, তবে একটি তালিকা, কারণ এটি দ্রুত দেখার মতো জিনিসগুলিকে সমর্থন করে না।
টমাস আহলে

আপনি এখনও করতে পারেন: >>> এলোমেলো.চয়েস (তালিকা (সেট (পরিসীমা (5))) >>> 4 আদর্শ নয় তবে এটি যদি আপনার একেবারে প্রয়োজন হয় তবে তা করবে।
নীলা

1

আপনি কি কেবল সেট / অ্যারের আকার / দৈর্ঘ্য পেতে পারেন না, 0 এবং আকার / দৈর্ঘ্যের মধ্যে একটি এলোমেলো সংখ্যা তৈরি করতে পারেন, তারপরে যে সংখ্যার সূচকটি মেলে সেই উপাদানটিকে কল করতে পারেন? হ্যাশসেটের একটি। সাইজ () পদ্ধতি রয়েছে, আমি নিশ্চিত।

সাইয়েডোকোডে -

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

এটি কেবল তখনই কাজ করে যদি প্রশ্নে থাকা ধারকটি এলোমেলো সূচী অনুসন্ধানটি সমর্থন করে। অনেক ধারক বাস্তবায়ন (যেমন, হ্যাশ টেবিল, বাইনারি গাছ, লিঙ্কযুক্ত তালিকাগুলি) করে না।
ডেভিড হ্যালি

1

পিএইচপি, ধরে নিচ্ছে "সেট" একটি অ্যারে:

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

মার্সেন টুইস্টার ফাংশনগুলি আরও ভাল তবে পিএইচপি-তে অ্যারে_রেন্ডের সমান এমটি নেই।


সর্বাধিক সেট বাস্তবায়নের আত একটি পেতে আছে (ঝ) অথবা ইন্ডেক্স অপারেটর, তাই আইডি না না অনুমান কেন ওপি তার একটি সেট নিদিষ্ট
DownloadPizza

1

আইকনটিতে একটি সেট টাইপ এবং একটি এলোমেলো-উপাদান উপাদান অপারেটর, unary "?" রয়েছে, তাই অভিব্যক্তি

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

দেখে মনে হচ্ছে এগুলি নিচু করা হয়েছে কারণ কর্কশ জাভা অভিধান (বা তথাকথিত লিংকডহ্যাশসেট, যাই হোক না কেন তা) "এলোমেলোভাবে অ্যাক্সেস" করা যায় না (যা কী দ্বারা অ্যাক্সেস করা হচ্ছে, আমার ধারণা)। জাভা বকাঝকা আমাকে এত হাসায়
ফেডেরিকো বেরাসেত্তুই

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

মজাদার জন্য আমি প্রত্যাখ্যানের নমুনার উপর ভিত্তি করে একটি র‌্যান্ডমহ্যাশসেট লিখেছিলাম। এটি কিছুটা হ্যাকি, যেহেতু হ্যাশম্যাপ আমাদের সরাসরি এটির টেবিলটি অ্যাক্সেস করতে দেয় না, তবে এটি ঠিক কাজ করা উচিত।

এটি কোনও অতিরিক্ত মেমরি ব্যবহার করে না এবং দেখার সময় হে (1) মোড়িত। (কারণ জাভা হ্যাশ টেবিলটি ঘন)।

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

সঙ্গে পেয়ারা আমরা 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

পিএইচপি, এমটি ব্যবহার করে:

$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

দুর্ভাগ্যক্রমে, কোনও স্ট্যান্ডার্ড লাইব্রেরি সেট ধারকগুলির মধ্যে দক্ষতার সাথে এটি (ও (এন) এর চেয়ে ভাল) করা যায় না।

এটি অদ্ভুত, যেহেতু হ্যাশ সেটগুলির পাশাপাশি বাইনারি সেটগুলিতে এলোমেলোভাবে পিক ফাংশন যুক্ত করা খুব সহজ। একটি হ্যাশ সেট ছড়িয়ে না দেওয়ার জন্য, আপনি হিট না হওয়া পর্যন্ত আপনি এলোমেলো এন্ট্রি চেষ্টা করতে পারেন। বাইনারি গাছের জন্য, আপনি সর্বোচ্চ ও (লগ 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] পেয়েছি তাই বিতরণটি ভাল হয়।

আমি নিজের জন্য একই সমস্যাটির সাথে লড়াই করেছি এবং আমি এখনও আবহাওয়া স্থির করে নি নি যে আরও কার্যকর পিকের পারফরম্যান্স লাভটি পাইথন ভিত্তিক সংগ্রহ ব্যবহারের ওভারহেডের পক্ষে মূল্যবান। আমি অবশ্যই এটি পরিমার্জন করতে এবং এটি সি তে অনুবাদ করতে পারি, তবে এটি আমার পক্ষে আজ খুব বেশি কাজ :)


1
আমার মনে হয় এটি বাইনারি ট্রিতে প্রয়োগ করা হয়নি কারণ এই জাতীয় পদ্ধতিটি আইটেমগুলি অভিন্নভাবে গ্রহণ করবে না। যেহেতু তাদের বাম / ডান বাচ্চাদের ছাড়া নোড, তাই এমন পরিস্থিতি দেখা দিতে পারে যেখানে বাম সন্তানের ডান সন্তানের চেয়ে বেশি আইটেম থাকে (বা বিপরীতে), ডান (বা বাম) সন্তানের কোনও আইটেম বাছাই করা আরও সম্ভাব্য।
উইলেম ভ্যান ওনসেম

1
@ কমসোফট: এজন্য আমি প্রতিটি সাবট্রির আকার সংরক্ষণ করি, তাই আমি তাদের উপর ভিত্তি করে আমার সম্ভাবনাগুলি বেছে নিতে পারি।
থমাস আহলে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.