একটি এনাম থেকে একটি এলোমেলো মান চয়ন করবেন?


161

আমার যদি এ জাতীয় এনাম থাকে:

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

এলোমেলোভাবে একটি বাছাই করার সেরা উপায় কী? এটি উত্পাদন মানের বুলেটপ্রুফ হওয়ার দরকার নেই, তবে মোটামুটি এমনকি বিতরণটিও দুর্দান্ত।

আমি এই মত কিছু করতে পারে

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

তবে এর চেয়ে ভাল উপায় আর কি আছে? আমি মনে করি এটি এমন একটি বিষয় যা আগে حل করা হয়েছে।


আপনার সমাধানটি কী ভুল বলে মনে করেন? এটি আমার কাছে বেশ ভাল লাগছে।
রাষ্ট্রপতি জেমস কে পোলক

1
@ গ্রেগস - সমস্যাটি হ'ল প্রতিটি কলকে Letter.values()অভ্যন্তরীণ Letterমান অ্যারের একটি নতুন অনুলিপি তৈরি করতে হয়।
স্টিফেন সি

উত্তর:


144

কেবলমাত্র আমি প্রস্তাব দিচ্ছি ফলাফলটি ক্যাশে করা 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));
  }
}

8
আপনি যদি এটি দরকারী হিসাবে বিবেচনা করেন, আপনি এটি করার জন্য একটি ইউটিলিটি ক্লাস তৈরি করতে পারেন। তালিকা তৈরির জন্য ক্লাস <টি> প্রাপ্ত কন্সট্রাক্টরের সাথে র্যান্ডমইনাম <টি এনামকে বাড়িয়ে তোলে> এর মতো কিছু।
হিলিওস

15
values()অ্যারে রূপান্তরিত করার বিন্দুটি আমি সত্যিই দেখতে পাচ্ছি না একটি অবিশ্বাস্য তালিকায়। VALUESবস্তুর ইতিমধ্যে ঘোষিত হওয়ার শক্তি কর্মদক্ষতার দ্বারা encapsulated হয় private। এটি তৈরি করা সহজ এবং আরও দক্ষ হবে private static final Letter[] VALUES = ...
স্টিফেন সি

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

1
@ ক্লেটাস: এনাম.ভ্যালোস () প্রতিটি অনুরোধের জন্য একটি নতুন অ্যারে ফিরিয়ে দেবে, সুতরাং এটি অন্য জায়গায় পাস / ব্যবহার করার আগে এটিকে মোড়ানো করার দরকার নেই।
চিআই

5
ব্যক্তিগত স্ট্যাটিক চূড়ান্ত চিঠি [] মূল্য ... ঠিক আছে U এটি প্রাইভেট তাই এটি অবিচ্ছিন্ন। আপনার কেবলমাত্র সর্বজনীন র‌্যান্ডম লেটার () পদ্ধতি দরকার যা স্পষ্টতই একটি মান প্রদান করে। স্টিফেন সি ঠিক আছে।
হেলিওস

126

আপনার সমস্ত এলোমেলো এনামগুলির জন্য আপনার প্রয়োজনীয় একটি একক পদ্ধতি:

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

যা আপনি ব্যবহার করবেন:

randomEnum(MyEnum.class);

আমি সিকিওরর্যান্ডমটিও এইভাবে ব্যবহার করতে পছন্দ করি :

private static final SecureRandom random = new SecureRandom();

1
ঠিক আমি খুঁজছেন ছিল কি. আমি স্বীকৃত উত্তরের মতো করছিলাম এবং যখন আমার দ্বিতীয় এনাম থেকে র্যান্ডমাইজ করা দরকার তখন তা আমাকে বয়লারপ্লেট কোড দিয়ে রেখেছিল। এছাড়াও, কখনও কখনও SecureRandom সম্পর্কে ভুলে যাওয়া সহজ। ধন্যবাদ।
সিয়ামাস্টার

আপনি আমার মন পড়েন, আমি আমার এলোমেলো সত্তা জেনারেটর পরীক্ষার ক্লাসে যুক্ত করতে ঠিক কী খুঁজছিলাম। সহায়তার জন্য ধন্যবাদ
রোক সোসা

43

এর পরামর্শ মিশ্রন 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<E>> {

        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<E>>,।



1
খুব পুরানো উত্তর আমি জানি, তবে তা হওয়া উচিত নয় E extends Enum<E>?
লিনো - ভোট

1
@ লিনো: স্বচ্ছতার জন্য সম্পাদিত; আমি মনে করি না যে এটি সঠিক পরামিতি পরামিতি অনুমিত জন্য প্রয়োজন , কিন্তু আমি সংশোধন স্বাগত জানাই; new RandomEnum<>(Season.class)জাভা since থেকে যে অনুমোদিত তা নোট করুন
ট্র্যাশগোড

RandomEnumআপনি যদি এটি বান্ডেল করে কেন্দ্রীয়ভাবে প্রকাশ করতে চান তবে এই একক শ্রেণিটি একটি মাইক্রো লাইব্রেরি হিসাবে দুর্দান্ত হবে।
গ্রেগ চাবালা


10

স্টেফেন সি ও হেলিওসের সাথে সম্মত হন। এনুম থেকে এলোমেলো উপাদান আনার আরও ভাল উপায়:

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


5

এটি সম্ভবত আপনার লক্ষ্য অর্জনের সবচেয়ে সংক্ষিপ্ত উপায় you আপনাকে যা করতে হবে তা হল কল করা Letter.getRandom()এবং আপনি একটি এলোমেলোভাবে এনাম লেটার পাবেন।

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

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

4

একটি অ্যারের থেকে এলোমেলো মান বাছাই করার জন্য একটি ফাংশন থাকা সম্ভবত সবচেয়ে সহজ। এটি আরও সাধারণ, এবং কল করার জন্য সহজ straight

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

যেমন কল:

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

4

এখানে এমন একটি সংস্করণ যা শাফল এবং স্ট্রিম ব্যবহার করে

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

4

সরল কোটলিন সমাধান S

MyEnum.values().random()

random()Collectionঅবজেক্টের বেস কোটলিনে অন্তর্ভুক্ত একটি ডিফল্ট এক্সটেনশন ফাংশন । কোটলিন ডকুমেন্টেশন লিঙ্ক

আপনি যদি এটি কোনও এক্সটেনশন ফাংশন দিয়ে সহজ করতে চান তবে এটি চেষ্টা করুন:

inline fun <reified T : Enum<T>> random(): T = enumValues<T>().random()

// Then call
random<MyEnum>()

এটি আপনার এনাম ক্লাসে স্থির করতে। my.package.randomআপনার এনাম ফাইলটিতে আমদানি করার বিষয়টি নিশ্চিত করুন

MyEnum.randomValue()

// Add this to your enum class
companion object {
    fun randomValue(): MyEnum {
        return random()
    }
}

আপনার যদি এনামের উদাহরণ থেকে এটি করার দরকার হয় তবে এই এক্সটেনশনটি চেষ্টা করে দেখুন

inline fun <reified T : Enum<T>> T.random() = enumValues<T>().random()

// Then call
MyEnum.VALUE.random() // or myEnumVal.random() 

3

আপনি যদি পরীক্ষার জন্য এটি করেন আপনি কুইকচেক ব্যবহার করতে পারেন ( এটি একটি জাভা বন্দর যা আমি কাজ করছি )।

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

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

এটি সমস্ত আদিম ধরণের, প্রকারের রচনা, সংগ্রহ, বিভিন্ন বিতরণ ফাংশন, সীমানা ইত্যাদি সমর্থন করে It

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

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

কুইকচেকের সুবিধা হ'ল আপনি একটি নির্দিষ্টকরণের ভিত্তিতে পরীক্ষাগুলি সংজ্ঞায়িত করতে পারেন যেখানে প্লেইন টিডিডি পরিস্থিতিগুলির সাথে কাজ করে।


আকর্ষণীয় দেখাচ্ছে। আমি চেষ্টা করে দেখতে হবে।
নিক হেইনার

কিছু কাজ না করলে আপনি আমাকে মেইল ​​করতে পারেন। আপনার 0.5b সংস্করণ ব্যবহার করা উচিত।
টমাস জং

2

এটি এনামে একটি এলোমেলো ফাংশন বাস্তবায়নের জন্য আইজার।

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


1

আমি অনুমান করি যে এই একক-লাইন-রিটার্ন পদ্ধতিটি এত সাধারণ কাজের ক্ষেত্রে ব্যবহারের জন্য যথেষ্ট দক্ষ:

public enum Day {
    SUNDAY,
    MONDAY,
    THURSDAY,
    WEDNESDAY,
    TUESDAY,
    FRIDAY;

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

    public static void main(String[] args) {
        System.out.println(Day.getRandom());
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.