2009-12-29 16 views
107

अगर मैं इस तरह की एक enum है:जावा: एक enum से एक यादृच्छिक मूल्य उठाओ?

public enum Letter { 
    A, 
    B, 
    C, 
    //... 
} 

का सबसे अच्छा तरीका एक बेतरतीब ढंग से लेने के लिए क्या है? इसे उत्पादन गुणवत्ता बुलेटप्रूफ होने की आवश्यकता नहीं है, लेकिन एक काफी वितरण भी अच्छा होगा।

मैं इस

private Letter randomLetter() { 
    int pick = new Random().nextInt(Letter.values().length); 
    return Letter.values()[pick]; 
} 

की तरह कुछ कर सकता है लेकिन वहाँ एक बेहतर तरीका है? मुझे लगता है कि यह ऐसा कुछ है जिसे पहले हल किया गया है।

+0

तुम्हें क्या लगता है अपने समाधान के साथ गलत क्या है? यह मेरे लिए बहुत अच्छा लग रहा है। –

+1

@ ग्रेग्स - समस्या यह है कि 'Letter.values ​​()' को प्रत्येक कॉल को आंतरिक 'पत्र' मान सरणी की एक नई प्रति बनाना है। –

+0

डर्न, मैं बस एक ही सवाल पूछने जा रहा था। अच्छा एक (+1) –

उत्तर

104

एकमात्र चीज जो मैं सुझाऊंगा वह values() के परिणाम को कैशिंग कर रही है क्योंकि प्रत्येक कॉल एक सरणी प्रतिलिपि बनाता है। साथ ही, प्रत्येक बार Random न बनाएं। एक रखें इसके अलावा आप जो कर रहे हैं वह ठीक है। तो:

public enum Letter { 
    A, 
    B, 
    C, 
    //... 

    private static final List<Letter> VALUES = 
    Collections.unmodifiableList(Arrays.asList(values())); 
    private static final int SIZE = VALUES.size(); 
    private static final Random RANDOM = new Random(); 

    public static Letter randomLetter() { 
    return VALUES.get(RANDOM.nextInt(SIZE)); 
    } 
} 
+7

यदि आप इसे उपयोगी मानते हैं, तो आप इसे करने के लिए उपयोगिता वर्ग बना सकते हैं। सूची बनाने के लिए कक्षा प्राप्त करने वाले कन्स्ट्रक्टर के साथ RandomEnum helios

+12

मुझे वास्तव में 'मान() 'सरणी को एक अपरिवर्तनीय सूची में परिवर्तित करने का बिंदु नहीं दिख रहा है। 'VALUES' ऑब्जेक्ट पहले से ही 'निजी' घोषित किए जाने के आधार पर encapsulated है। यह 'निजी स्थिर अंतिम पत्र [] VALUES = ... 'बनाने के लिए आसान और अधिक कुशल होगा। –

+4

जावा में Arrays mutable हैं इसलिए यदि आपके पास एक सरणी फ़ील्ड है और इसे सार्वजनिक विधि में वापस कर दें तो कॉलर इसे संशोधित कर सकता है और यह निजी दायर को संशोधित करता है ताकि आपको सरणी को प्रतिलिपि बनाने की आवश्यकता हो। यदि आप उस विधि को कई बार कॉल करते हैं तो यह एक समस्या हो सकती है ताकि आप अनावश्यक रक्षात्मक प्रतिलिपि से बचने के बजाय इसे एक अपरिवर्तनीय सूची में डाल सकें। – cletus

37

, cletus और helios के सुझावों का मेल

import java.util.Random; 

public class EnumTest { 

    private enum Season { WINTER, SPRING, SUMMER, FALL } 

    private static final RandomEnum<Season> r = 
     new RandomEnum<Season>(Season.class); 

    public static void main(String[] args) { 
     System.out.println(r.random()); 
    } 

    private static class RandomEnum<E extends Enum> { 

     private static final Random RND = new Random(); 
     private final E[] values; 

     public RandomEnum(Class<E> token) { 
      values = token.getEnumConstants(); 
     } 

     public E random() { 
      return values[RND.nextInt(values.length)]; 
     } 
    } 
} 

संपादित करें: ओह, मैं घिरे प्रकार पैरामीटर भूल गया, <E extends Enum>

+1

यह भी देखें [* क्लास लिटरेल्स रनटाइम-टाइप टोकन *] (http://docs.oracle.com/javase/tutorial/extra/generics/literals.html)। – trashgod

3

यदि आप परीक्षण के लिए ऐसा करते हैं तो आप Quickcheck (this is a Java port I've been working on) का उपयोग कर सकते हैं।

import static net.java.quickcheck.generator.PrimitiveGeneratorSamples.*; 

TimeUnit anyEnumValue = anyEnumValue(TimeUnit.class); //one value 

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

import static net.java.quickcheck.generator.PrimitiveGeneratorsIterables.*; 

for(TimeUnit timeUnit : someEnumValues(TimeUnit.class)){ 
    //..test multiple values 
} 

Quickcheck का लाभ यह है कि आप को परिभाषित कर सकते है specification पर आधारित परीक्षण जहां सादे टीडीडी परिदृश्यों के साथ काम करता है।

public static <T extends Enum<?>> T randomEnum(Class<T> clazz){ 
     int x = random.nextInt(clazz.getEnumConstants().length); 
     return clazz.getEnumConstants()[x]; 
    } 

जो तुम का उपयोग करेंगे::

randomEnum(MyEnum.class); 

मैं भी रूप में SecureRandom का उपयोग करना पसंद:

+0

दिलचस्प लग रहा है। मुझे इसे आज़मा देना होगा। –

+0

अगर कोई काम नहीं करता है तो आप मुझे मेल कर सकते हैं। आपको 0.5 बी संस्करण का उपयोग करना चाहिए। –

4
Letter lettre = Letter.values()[(int)(Math.random()*Letter.values().length)]; 
78

एक एकल विधि सब आप अपने सभी यादृच्छिक enums के लिए की जरूरत है

private static final SecureRandom random = new SecureRandom(); 
2

यह शायद आसान है एक सरणी से एक यादृच्छिक मूल्य लेने के लिए एक समारोह है। यह अधिक सामान्य है, और कॉल करने के लिए सीधा है।

<T> T randomValue(T[] values) { 
    return values[mRandom.nextInt(values.length)]; 
} 

तो जैसे कॉल:

MyEnum value = randomValue(MyEnum.values()); 
2

यह है eaiser enum पर एक यादृच्छिक समारोह को लागू करने।

public enum Via { 
    A, B; 

public static Via viaAleatoria(){ 
    Via[] vias = Via.values(); 
    Random generator = new Random(); 
    return vias[generator.nextInt(vias.length)]; 
    } 
} 

और फिर आप वर्ग से इसे कहते आप इसे इस

public class Guardia{ 
private Via viaActiva; 

public Guardia(){ 
    viaActiva = Via.viaAleatoria(); 
} 
8

तरह की जरूरत है Stphen सी & HELIOS साथ सहमत हूँ। बेहतर तरीका Enum से यादृच्छिक तत्व लाने के लिए है:

public enum Letter { 
    A, 
    B, 
    C, 
    //... 

    private static final Letter[] VALUES = values(); 
    private static final int SIZE = VALUES.length; 
    private static final Random RANDOM = new Random(); 

    public static Letter getRandomLetter() { 
    return VALUES[RANDOM.nextInt(SIZE)]; 
    } 
} 
10

सिंगल लाइन

return Letter.values()[new Random().nextInt(Letter.values().length)]; 
2

यहाँ फेरबदल का उपयोग करता है और धाराओं

List<Direction> letters = Arrays.asList(Direction.values()); 
Collections.shuffle(letters); 
return letters.stream().findFirst().get(); 
2

कि एक संस्करण यह शायद को प्राप्त करने का सबसे संक्षिप्त तरीके से है आपका लक्ष्य। आपको केवल Letter.getRandom() पर कॉल करना है और आपको एक यादृच्छिक एनम पत्र मिलेगा।

public enum Letter { 
    A, 
    B, 
    C, 
    //... 

    public static Letter getRandom() { 
     return values()[(int) (Math.random() * values().length)]; 
    } 
} 
3

मैं इस का प्रयोग करेंगे:

private static Random random = new Random(); 

public Object getRandomFromEnum(Class<? extends Enum<?>> clazz) { 
    return clazz.values()[random.nextInt(clazz.values().length)]; 
} 
संबंधित मुद्दे