Guava - how can I generate a random number using R

2019-07-17 22:14发布

问题:

Google's Guava library provides a great class called Range, it has many useful methods like greaterThan(x), open(x,y), etc. I am wondering if there is any way of applying such method to generate a random number within a Range?

回答1:

I would not suggest using a range for this basic application.

The easiest method to use is the already implemented Random class.

Here is how to use the class:

For getting a random integer of any value:

Random r = new Random();
r.nextInt();

For getting a random integer in a range of min x, max y:

Random r = new Random();
r.nextInt(y - x) + x;

This is the most basic way of getting a random number in a range. I bet there is a getMin and getMax method in the range class, so use that for x and y.

Also, if you want a random number greater than a min value of x, just do:

Random r = new Random();
Math.abs(r.nextInt().nextInt()) + x;

^The code above generates any positive integer, and the x ensures the min value.

-or-

nextInt(Integer.MAX_VALUE - (x + 1)) + (x + 1)

-as suggested by ColinD Hope this helps. -Classic



回答2:

Like Louis says there's no built-in way to do this, but there are a couple of fairly straightforward options. Note that we have to assume all Range instances are bounded on both sides - you cannot select a random value from an unbounded or non-discrete range (e.g. (-∞..0]).

The easiest to implement solution is to simply convert the Range into a ContiguousSet, from which you can select a random value in linear time. This has the advantage of working for any discrete type, not just Range<Integer>.

public static C random(Range<C> range, DiscreteDomain<C> domain) {
  Set<C> set = ContiguousSet.create(range, domain);
  int index = random.nextInt(set.size());
  return Iterables.get(set, index);
}

Of course constant time would be better, especially for large ranges. Canonicalizing the Range first reduces the number of cases we have to handle, and we can use the f(y-x) + x pattern JClassic suggests.

public static int random(Range<Integer> range) {
  checkArgument(range.hasLowerBound() && range.hasUpperBound(),
      "Cannot select a random element from unbounded range %s", range);
  Range<Integer> canonical = range.canonical(DiscreteDomain.integers());
  return random.nextInt(canonical.upperEndpoint() - canonical.lowerEndpoint())
      + canonical.lowerEndpoint();
}

You can extend this easily for Long with Random.nextLong() (but note that Random.nextLong() cannot return all long values, so SecureRandom would be preferable).