To get a Random enum you need something along those lines.
<code>
public Days randomDay() {
Days[] days = Days.values();
return days[(int) (Math.random() * days.length)];
}
</code>
But what if I want to generalize this code.
Is it possible that my method accepts just any enum, gets it's
.values, gets one Random value from it and returns it?
Anybody care to share his ideas and maybe some code?
Greetings,
--
Daniel Berger
Send files in free open formats.
I guess you could write a suitable generic static method with
the enum's Class object as its argument. It might be tricky, though:
The generic markup for Enum itself is sort of funky and circular-
looking, and might make the method's signature unpleasantly intricate.
But choosing a random element from a group of some kind is a common
enough operation that I think limiting the operation to enums would be
sort of silly. A method to pluck a random T from a T[] or from a
Collection<T> is simple enough, and probably more widely useful.
For the case where you want a random selection from a group whose
size and membership are not known in advance, you can use something
like (untested):
public class Sampler<T> {
private final Random rand = new Random();
private int offered;
private T chosen;
public void offer(T obj) {
++offered;
if (rand.nextInt(offered) == 0)
chosen = obj;
}
public T choose() {
return chosen;
}
}
// usage:
Sampler<Thing> sampler = new Sampler<Thing>();
for (Thing thing; (thing = getAnotherThing()) != null; )
sampler.offer(thing);
Thing theChosenThing = sampler.choose();
Or,
public class RandomDayer
{
private static final Random rand = new Random();
public static Days randomDay()
{
return Days.values() [rand.nextInt( Days.values().length )];
}
}
> But what if I want to generalize this code.
> Is it possible that my method accepts just any enum, gets it's [sic]
> .values, gets one Random value from it and returns it?
>
If you can pass a Class instance to the method, as Eric Sosman
suggested.
public class RandomEnum // untested, not even compiled yet
{
private static final Random rand = new Random();
public static <E extends Enum<E>> E random( Class <E> clazz )
{
E [] values = clazz.getEnumConstants();
return values [rand.nextInt( values.length )];
}
}
As to Eric's fear that this is "unpleasantly intricate", we just have
to get over it.
In use it's very simple. Given an enum 'Foo':
Foo value = RandomEnum.random( Foo.class );
--
Lew
First, I would use new Random().nextInt(days.length), instead of
Math.random() * days.length;
Then I would consider writing these methods:
// Warning, untested.
public static <T extends Enum<T>> T random(Class<T> type) {
return random(type.getEnumConstants());
}
public static <T> T random(T...values) {
return random(new Random(), values);
}
public static <T extends Enum<T>> T random(Random random, Class<T> type)
{
return random(random, type.getEnumConstants());
}
public static <T> T random(Random random, T...values) {
return values[random.nextInt(values.length)];
}
Then you can do things like random(Days.class) or
random("One", "String", "At", "Random")
--
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
>But what if I want to generalize this code.
>Is it possible that my method accepts just any enum, gets it's
>.values, gets one Random value from it and returns it?
For code to handle a generating a random particular enum, see
http://mindprod.com/jgloss/pseudorandom.html#ENUM
I think the only other thing you need to know is all enums have an
abstract superclass public abstract class Enum<E extends Enum<E>>
--
Roedy Green Canadian Mind Products
http://mindprod.com
http://thecovemovie.com : The Cove: a documentary about Japan's secret atrocities against dolphins.
[...]
> private static final Random rand = new Random();
>
> public static <E extends Enum<E>> E random( Class <E> clazz )
> {
> E [] values = clazz.getEnumConstants();
> return values [rand.nextInt( values.length )];
> }
Excellent! Let me see if I got this right: Given a generic parameter
named E whose type extends Enum<E>, the public static method random()
returns a value of type E when passed a class token, Class<E>.
[...]
> As to Eric's fear that this is "unpleasantly intricate", we just have
> to get over it.
I also thought this would be more difficult, but "The direct
superclass of an enum type named E is Enum<E> [1]."
I just wish there were a common place to document the implicit static
Enum methods [1] and the abstract class Enum methods [2].
[1]<http://java.sun.com/docs/books/jls/third_edition/html/classes.html
#8.9>
[2]<http://java.sun.com/javase/6/docs/api/java/lang/Enum.html>
--
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>
>return days[(int) (Math.random() * days.length)];
There are much better ways to do this. see
http://mindprod.com/jgloss/pseudorandom.html
This technique has the overhead of two double <-> int conversions.
Further, as a general principle, you get into trouble when you use
double when you want precise integer results.
This is what I would have suggested. It's pretty simple really. You
could define a similar method that takes an enum rather than a class and
returns a random value, it's just as easy to call getDeclaringClass() on
an enum and use this one method.
package randomenum;
import java.lang.annotation.ElementType;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class RandomEnum
{
public static void main( String[] args )
{
System.out.println( "Random TimeUnit: " +
randomEnum( TimeUnit.SECONDS ) );
System.out.println( "Random ElementType: " +
randomEnum( ElementType.FIELD ) );
}
static Enum<?> randomEnum( Enum<?> e )
{
return random( e.getDeclaringClass() );
}
private static final Random rand = new Random();
public static <E extends Enum<E>> E random( Class<E> clazz )
{
E[] values = clazz.getEnumConstants();
return values[rand.nextInt( values.length )];
}
}
OUTPUT:
run:
Random TimeUnit: MICROSECONDS
Random ElementType: LOCAL_VARIABLE
BUILD SUCCESSFUL (total time: 2 seconds)
And couldn't you make this generic, too? (I haven't tried it yet.)
public static <E extends Enum<E>> E random( Enum <E> e )
{
return random( e.getDeclaringClass() );
}
> private static final Random rand = new Random();
>
> public static <E extends Enum <E>> E random( Class <E> clazz )
> {
> E [] values = clazz.getEnumConstants();
> return values [rand.nextInt( values.length )];
> }
>
> }
> OUTPUT:
> run:
> Random TimeUnit: MICROSECONDS
> Random ElementType: LOCAL_VARIABLE
> BUILD SUCCESSFUL (total time: 2 seconds)
--
Lew
Thanks, Lew: My fears are (mostly) allayed. It looks like
type inference saves the day; I was worried that the caller
might have to write out a great big generic gobbledegook just
to invoke the method.
And I stand by my remarks on the usefulness of not limiting
the operation to enums alone, but on letting it work with many
kinds of groupings: arrays, Collections, and sequences.
--
Eric Sosman
eso...@ieee-dot-org.invalid
Since he's already unperturbed by the overhead of making
a brand-new array and copying the enum references into it, I
don't think he'll break into a flop sweat over two operations
on primitives.
--
Eric Sosman
eso...@ieee-dot-org.invalid
> markspace wrote:
>> static Enum<?> randomEnum( Enum<?> e )
> And couldn't you make this generic, too? (I haven't tried it yet.)
I could, but I wanted to demonstrate that it works with just
polymorphism too. It actually took me a while to realize that although
Enum itself couldn't be subclassed directly, Enum still works fine as a
super class capable of holding any enum.
Enum<?> e;
e = TimeUnit.SECONDS;
e = ElementType.FIELD;
Should compile just fine, and you can use nearly every method declared
in Enum because they're all polymorphic ('cept for finalize() and
clone() which aren't supported, and valueOf() which is static). All the
methods are final, too, but they all work polymorphically.
// works regardless of sub-type
String s = e.name();
int i = e.ordinal();
etc. Sometimes, polymorphism is better than generics, although in the
example I gave I think generic are actually a bit better, or it's a wash
if you're a bit charitable.
> Since he's already unperturbed by the overhead of making
>a brand-new array and copying the enum references into it, I
>don't think he'll break into a flop sweat over two operations
>on primitives.
I cut my teeth on a RAM-less vacuum tube-based LGP-30 computer with
software-emulated floating point, so I still mentally cringe at any
unnecessary floating point operations.
Even today, trivial floating point operations can chew up the clock
cycles.
For example, on a Pentium
FRDINT, round to int is 9 to 20 cycles.
FLD, load a double is 3 cycles.
FIST store as an int is 6 cycles.
In comparison, most integer operations complete in 1 clock. As a
general rule I try to avoid floating point whenever I don't want the
magnitude scaling or the fractional values. Any time you use floating
point to solve Diophantine problems you lose speed and create
squirrelly, off-by one-corner cases. A first cut solution is usually
only approximately correct. My rule of thumb is to reserve floating
point for times when approximately correct is adequate.
> static Enum<?> randomEnum( Enum<?> e )
> {
> return random( e.getDeclaringClass() );
> }
>
> private static final Random rand = new Random();
>
> public static <E extends Enum<E>> E random( Class<E> clazz )
> {
> E[] values = clazz.getEnumConstants();
> return values[rand.nextInt( values.length )];
> }
Two questions that may be of interest to the general audience.
1. What happens if you do simply "e.values()", rather than the
roundabout "getDeclaringClass" and "getEnumConstants"?
2. how do you get away with "E[] values"? Seems to me arrays and
generics are like trying to get oil and water to mix.
What type is getEnumConstants actually returning at run time?
>
>1. What happens if you do simply "e.values()", rather than the
>roundabout "getDeclaringClass" and "getEnumConstants"?
Answer: values() is a static method. Though you can write e.values()
that won't dynamically select the correct static method. Which static
method is chosen depends on the compile time type of the e reference,
not the run time object.
e.values() won't even compile. It's a static method declared on
subclasses of Enum, not Enum itself.
>
> 2. how do you get away with "E[] values"? Seems to me arrays and
> generics are like trying to get oil and water to mix.
> What type is getEnumConstants actually returning at run time?
>
T[] always works fine. It's trying to declare a "new" array where you
get into trouble (and then only a bit, unless you don't know what the
tricks are).
You really ought to get Effective Java by Joshua Bloch, Roedy. It goes
into this stuff and provides some excellent solutions.
No, it doesn't depend on the runtime type of e. No method is chosen.
"e.values()" is a syntax error. Period.
>
> FRDINT, round to int is 9 to 20 cycles.
>
> FLD, load a double is 3 cycles.
>
> FIST store as an int is 6 cycles.
>
> In comparison, most integer operations complete in 1 clock.
You must have a very old Pentium. I think float operations have also
taken 1 cycle since about 1999 or so. Doubles I think still take more
cycles, but floats are now equivalent to ints on most platforms as far
as execution speed is concerned. That includes many "small footprint"
platforms such as ARM-9 too. (But not most cell phone type apps.)
> Hi there,
>
> To get a Random enum you need something along those lines.
>
> <code>
> public Days randomDay() {
> Days[] days = Days.values();
>
> return days[(int) (Math.random() * days.length)];
> }
> </code>
>
> But what if I want to generalize this code.
> Is it possible that my method accepts just any enum, gets it's
> .values, gets one Random value from it and returns it?
>
> Anybody care to share his ideas and maybe some code?
>
> Greetings,
Thanks for the many suggestions, I got it working pretty easily with all
the help.
>You must have a very old Pentium
You are right. The Pentium is new, but the manual is circa 1993
--
Roedy Green Canadian Mind Products
http://mindprod.com
"There is an evil which ought to be guarded against, in the indefinite accumulation of property,
from the capacity of holding it in perpetuity by... corporations.
The power of all corporations aught to be limited in this respect.
The growing wealth acquired by them never fails to be a source of abuses."
~ James Madison (born: 1751-03-16 died: 1836-06-28 at age: 85)
>
>No, it doesn't depend on the runtime type of e. No method is chosen.
>"e.values()" is a syntax error. Period.
I did a few experiments:
Enum<?> e. e.values() is a syntax error, cannot find symbol
Enum e. e.values. is a syntax error, cannot find symbol
TimeUnit.SECONDS.values(); even though values is static, works.
At first, I thought there must be some deep mystery, but I think all
it amounts to is class Enum has no static method "values()". It has no
need of one. However enum TimeUnit does.
--
Roedy Green Canadian Mind Products
http://mindprod.com
"There is an evil which ought to be guarded against, in the indefinite accumulation of property,
Roedy Green wrote:
> I did a few experiments:
>
> Enum<?> e. e.values() is a syntax error, cannot find symbol
>
> Enum e. e.values. is a syntax error, cannot find symbol
>
> TimeUnit.SECONDS.values(); even though values is static, works.
>
> At first, I thought there must be some deep mystery, but I think all
> it amounts to is class Enum has no static method "values()". It has no
> need of one. However enum TimeUnit does.
markspace wrote at 12:39 EDT:
>> e.values() won't even compile. It's a static method declared on
>> subclasses of Enum, not Enum itself.
Let's go to the Javadocs, one of my favorite resolvers for Java library issues.
<http://java.sun.com/javase/6/docs/api/java/lang/Enum.html>
No 'values()' method shown.
What about the JLS, another great disambiguator?
<http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.9>
> In addition, if E is the name of an enum type,
> then that type has the following implicitly declared static methods:
> ...
> public static E[] values();
...
> the automatically generated methods (values() and valueOf(String))
Whaddaya know? You guys are right, and so is the documentation! It tells us
that 'values()' is a method of each specific 'enum' type, automatically
generated for that type, and that 'Enum<E>' does not contain that method.
Sometimes the official documentation can be soooo helpful.
--
Lew
>Sometimes the official documentation can be soooo helpful.
Just because you have the freakish ability to read Chinese from birth
does not mean everyone else is so endowed or should be.
There needs to be another sort of JLS written for ordinary mortals
that explains ALL the fine points with carefully selected concrete
examples and some discussion of why things are the way they are.
One of the main reasons I was so passionate about computers was I felt
the language used in math for proofs was way too fuzzy and ambiguous.
I loved the idea of a compiler with extremely rigid rules on what was
a valid sentence. The JLS language feels so fuzzy and deliberately
obscure, much like a insurance policy designed to keep the purchaser
from understanding it.
I hoped some day to invent a mathematics with a rigid computer
language for expressing its assertions, to try to eliminate the
slipperiness on what counted as legitimate argument. Others have done
this.
Roedy Green wrote:
> Just because you have the freakish ability to read Chinese from birth
> does not mean everyone else is so endowed or should be.
First of all, the docs I read are in English, not Chinese. Secondly, the docs
I pointed out are not so difficult as you pretend. You do those who attempt
to learn Java (better) a *huge* disservice by trying to dissuade them in this
way from reading the documentation.
> There needs to be another sort of JLS written for ordinary mortals
> that explains ALL the fine points with carefully selected concrete
> examples and some discussion of why things are the way they are.
Oh, come on. Have you actually tried reading the JLS? It's not that bad.
Sure, it isn't perfect, but it's pretty good. And the points I highlighted
about enum did explain the situation rather fully, especially when you take
the JLS and the API Javadocs together. That's a skill anyone can engage.
So don't pretend I have some super-human ability to read documentation,
flattering though that characterization be. I did what pretty much anyone
reading this newsgroup can do - I read the documentation. Try it - it's
really not that bad. Trust me.
--
Lew
You say that as though the two are mutually exclusive or even serve
the same purpose.
--
Lew
>Oh, come on. Have you actually tried reading the JLS? It's not that bad.
To you yes. To me it might as well be Chinese. Other people will rank
themselves at various points on the spectrum. I stand it awe of
people like you and Patricia who divine these entrails and come out
with such cogent findings.
he only way it ever makes any sense to me is if I already know what it
must mean.
It almost never clarifies. It just makes me ever less certain I know
how Java is supposed to work. Perhaps I am too much of a lawyer at
heart (maternal grandpa was a lawyer, so the genes are in there
somewhere) and I find multiple ways to interpret every sentence.
I persist in claiming that a much clearer and less ambiguous way to
give the same information is with a set of examples that cover all the
corner cases. This would be the main document that most programmers
would use to resolve fine points.
I had the same problem with mathematical proofs. It always seemed so
arbitrary how you could interpret each sentence. It feels like so much
handwaving to use a fuzzy language like English in proofs. You have
to decide beforehand what precisely what operations and inferences are
legit in proofs. Even the great mathematician Cauchy screwed up
because of the way English does not make sufficiently fine
distinctions.
There should also be some formal way of describing a language where
every sentence has unambiguous meaning and you have some way of
knowing if your description is complete. This would serve the
compiler-writer language lawyer purposes of the current JLS, and allow
automated compiler verification.
You then want to tie together your examples, the formal description
and the compiler to ensure they stay consistent, and complete, with
continuous automated retesting.