2011-12-04 6 views
17
में एक सूची से कई यादृच्छिक तत्वों उठाओ

तो कहते हैं कि मैंजावा

List<String> teamList = new LinkedList<String>() 
teamList.add("team1"); 
teamList.add("team2"); 
teamList.add("team3"); 
teamList.add("team4"); 
teamList.add("team5"); 
teamList.add("team6"); 

है वहाँ उठा का एक आसान तरीका है ... कहते हैं 3 बाहर एक ही उठा के बिना एक यादृच्छिक तरह से इस सूची में 6 तत्वों तत्व दो बार (या अधिक बार)?

उत्तर

47

इस प्रयास करें (जाहिर है, आप यहाँ ArrayList उपयोग करना चाहते हैं):

public static List<String> pickNRandom(List<String> lst, int n) { 
    List<String> copy = new LinkedList<String>(lst); 
    Collections.shuffle(copy); 
    return copy.subList(0, n); 
} 

मैं यह सोचते हैं रहा हूँ इनपुट सूची में कोई दोहराया तत्वों देखते हैं कि, यह भी मैं सावधानी बरतते हैं मूल सूची को छोड़ने के लिए एक प्रतिलिपि बनाने के लिए। इसे इस तरह कहा जाता है:

List<String> randomPicks = pickNRandom(teamList, 3); 
+1

वास्तव में यह एक बहुत अच्छा विचार है! बहुत बहुत धन्यवाद! – Yokhen

+1

IndexOutOfBoundsException से उपयोग योग्य सुरक्षा: वापसी n> copy.size()? copy.subList (0, copy.size()): copy.subList (0, n); – pawegio

+4

जब आपको केवल 3 तत्वों की आवश्यकता होती है तो पूरी सूची को शफ़ल करना बड़ी सूचियों के लिए बहुत अपमानजनक है। – Eyal

2

उपयोग

Collections.shuffle(teamList); 

सूची randomize करने के लिए, तो टीमों के माध्यम से teamList.remove(0);

सूची से एक समय में एक को दूर उदाहरण के लिए:

List<String> teamList = new LinkedList<String>(); 
    teamList.add("team1"); 
    teamList.add("team2"); 
    teamList.add("team3"); 
    teamList.add("team4"); 
    teamList.add("team5"); 
    teamList.add("team6"); 

    java.util.Collections.shuffle(teamList); 

    String[] chosen3 = new String[3]; 
    for (int i = 0; i < chosen3.length && teamList.size() > 0; i++) { 
    chosen3[i] = teamList.remove(0); 
    } 
+0

वास्तव में एक अच्छा विचार को छोड़कर अपनी सूची में यादृच्छिक 3 आइटम यह मानते हुए होगा परिवर्तन करने के लिए ठीक है आदेश। अन्यथा आप स्वयं को एक स्थानीय प्रतिलिपि बना सकते हैं (थोड़ा महंगा, लेकिन यह काम करता है)। मैं व्यक्तिगत रूप से 'हटाएं (teamList.size() - 1)' का उपयोग करता हूं ताकि अगर कार्यान्वयन एक अलग सूची में बदल जाता है तो इसमें कुशल होने का उच्चतम मौका होता है, लेकिन 'हटाएं (0)' भी काम करता है :) – corsiKa

+0

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

+1

लॉल, हमने अभी आंशिक रूप से वही बात कहा है। धन्यवाद ग्लोकोडर। – Yokhen

6

ints का एक सेट बनाएँ, और एक लूप में 0 और सूची की लंबाई के बीच यादृच्छिक संख्याओं को एक में रखें, जबकि सेट का आकार यादृच्छिक तत्वों की वांछित संख्या के बराबर नहीं है। सेट के माध्यम से जाएं, और सूची में संख्याओं द्वारा इंगित सूची तत्वों को चुनें। इस तरह आपकी मूल सूची बरकरार रहेगी।

+0

जो भी काम करेगा। 1+ –

+1

अच्छा दृष्टिकोण जब तक कि आप 1000 तत्व सूची में 999 तत्वों को चुनना नहीं चाहते हैं :) – waxwing

+1

यह एक बहुत अच्छा विचार है :) लेकिन इंडेक्स की वैकल्पिक सूची का ट्रैक रखना थोड़ा मुश्किल हो सकता है। लेकिन वैसे भी धन्यवाद :) – Yokhen

5

shuffle दृष्टिकोण सबसे बेवकूफ है: उसके बाद, पहले के तत्व बिल्कुल वही हैं जो आपको चाहिए।

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

2

सभी अच्छे विचार लेकिन शफलिंग महंगा है। अधिक कुशल विधि (आईएमओ) एक गिनती नियंत्रित पाश कर रही है और 0 और एन के बीच यादृच्छिक int चुन रही है; जहां शुरुआत में आपकी सूची की लंबाई के बराबर है।

लूप के प्रत्येक पुनरावृत्ति में आप चयनित आइटम को सूची में एन -1 पर आइटम के साथ स्वैप करते हैं और एक से कमी करते हैं। इस तरह आप एक ही तत्व को दो बार चुनने से बचते हैं और चयनित वस्तुओं की एक अलग सूची नहीं रखना है।

+0

जो एक अच्छा विकल्प की तरह लगता है, लेकिन इसके लिए मुझे थोड़ा और काम की आवश्यकता होगी। वैसे भी धन्यवाद :) – Yokhen

+0

यह अल्फ के समाधान के बराबर है, है ना? सिवाय इसके कि वह तत्वों को शुरुआत में रखता है। – waxwing

4

आप reservoir sampling का भी उपयोग कर सकते हैं।

यह लाभ है कि आपको पहले से ही स्रोत सूची के आकार को जानने की आवश्यकता नहीं है (उदाहरण के लिए यदि आपको List के बजाय Iterable दिया गया है।) यह भी कुशल है जब स्रोत सूची यादृच्छिक नहीं है- आपके उदाहरण में LinkedList की तरह पहुंच।

+0

उत्तर के लिए धन्यवाद। हालांकि क्या आप विस्तार से विस्तार से व्याख्या कर सकते हैं? मैं जिस विधि को आपने समझाया है उससे मैं बहुत अपरिचित हूं। धन्यवाद। – Yokhen

+0

@ योकेन, विचार यह है कि यदि (उदाहरण के लिए) आप 3 आइटम चुन रहे हैं, और आपने इनपुट सूची में 40 वां आइटम माना है, तो उस बिंदु पर आपने 3 में से 3 आइटम चुने हैं, इसलिए अंतिम आइटम में 3/आउटपुट सरणी में होने का 40 मौका। यदि आप विकिपीडिया लेख में छद्म कोड देखते हैं, तो आप देखेंगे कि आखिरी ऑपरेशन ('आर ← यादृच्छिक (0 .. i); अगर (आर <के) तो एक [आर] ← एस [i]') कर देता है। – finnw

+0

+1 उत्कृष्ट विकल्प। – trashgod

0

यहाँ, का उपयोग कर जावा धाराओं यह करने का एक तरीका है मूल सूची की एक प्रति बनाने के लिए हो रही है या यह फेरबदल के बिना:

public static List<String> pickRandom(List<String> list, int n) { 
    if (n > list.size()) { 
     throw new IllegalArgumentException("not enough elements"); 
    } 
    Random random = new Random(); 
    return IntStream 
      .generate(() -> random.nextInt(list.size())) 
      .distinct() 
      .limit(n) 
      .mapToObj(list::get) 
      .collect(Collectors.toList()); 
} 

ध्यान दें: यह अक्षम हो सकता है जब n भी सूची के करीब है विशाल सूचियों के लिए आकार।

0
int[] getRandoms(int[] ranges, int n, int[] excepts) { 
    int min = ranges[0]; 
    int max = ranges[1]; 

    int[] results = new int[n]; 
    for (int i = 0; i < n; i++) { 
     int randomValue = new Random().nextInt(max - min + 1) + min; 
     if (ArrayUtils.contains(results, randomValue) || ArrayUtils.contains(excepts, randomValue)) { 
      i--; 
     } else { 
      results[i] = randomValue; 
     } 
    } 
    return results; 
} 

util वर्ग

public static class ArrayUtils { 

    public static boolean contains(int[] array, int elem) { 
     return getArrayIndex(array, elem) != -1; 
    } 

    /** Return the index of {@code needle} in the {@code array}, or else {@code -1} */ 
    public static int getArrayIndex(int[] array, int needle) { 
     if (array == null) { 
      return -1; 
     } 
     for (int i = 0; i < array.length; ++i) { 
      if (array[i] == needle) { 
       return i; 
      } 
     } 
     return -1; 
    } 
} 

का उपयोग कर

int[] randomPositions = getRandoms(new int[]{0,list.size()-1}, 3, new int[]{0,1}); 

यह आइटम 0 और मद 1