5

How can I generate a random number from two different ranges?

For example: one number from 10-20 and 50-60.

I know how to generate a random number from one range (1-13):

Random rnd = new Random();
int num = rnd.Next(1, 13);
4
  • msdn
    – user2844991
    Commented Nov 12, 2015 at 21:11
  • @avisikirov if you can generate for one how come you can't do it for the others you have the coded example that you posted..?
    – MethodMan
    Commented Nov 12, 2015 at 21:13
  • 1
    Could it be that OP wants to generate a single number that falls in the range of 10-20 or 50-60, and not two separate numbers from those ranges?
    – jaredk
    Commented Nov 12, 2015 at 21:14
  • @jaredk ah, good thinking. In that case I'd suggest the OP generates 3 numbers; one for each range and then a third to dictate which one to use. Like Robert did in his answer, now that I look at it.
    – sab669
    Commented Nov 12, 2015 at 21:29

5 Answers 5

6
int num = rnd.Next(1, 3)==1 ? rnd.Next(10, 21) : rnd.Next(50,61);

or

int num = rnd.Next(10, 32);
if (num>20) num+=29;

or just for fun (don't use with large ranges, and runs slow anyhow):

var ranges=new []{ Tuple.Create(10,20), Tuple.Create(50,60)};
var rnd=new Random();
var possible=ranges.Select(x=>Enumerable.Range(x.Item1,x.Item2-x.Item1+1))
  .SelectMany(x=>x)
  .Distinct();
var num=possible.Skip(rnd.Next(0,possible.Count())).First();
8
  • It should be rnd.Next(1, 3). The max value is exclusive. Commented Nov 12, 2015 at 21:17
  • @RobertMcKee Thank you, your first method is wonderful. but can I use this method for taking random numbers from 3 groups or even more? Commented Nov 13, 2015 at 12:13
  • Sure. The 3rd method can take however many groups you need, just add another Tuple. The first and second methods can be modified to handle more groups. Modifying the first to handle 3 groups would look like: switch(rnd.Next(1,4)){ case 1: num=rnd.Next(10,21); break; case 2: num=rnd.Next(50,61); break; case 3: num=rnd.Next(90,101); break;} Commented Nov 13, 2015 at 20:04
  • The first method will favor some numbers more than others if the size of the ranges are not the same however. Like 1-2 and 10-19. 1 would show up 25% of the time, 2 would show up 25% of the time, and each number 10-19 would show up 5% of the time, so be careful. Commented Nov 13, 2015 at 20:06
  • Alternatively, you can do a modification of the second method. For 10-20, 50-60, 90-100, it would look like: int tmp=rnd.Next(0,33); int num; if (tmp<11) num=tmp+10; else if (tmp<22) num=tmp+39; else num=tmp+68; Commented Nov 13, 2015 at 20:10
2

Remember for the Next method, the lower bound is inclusive, while the upper bound is exclusive. How about:

var rand = new Random();
var num1 = rand.Next(10, 21);

var num2 = rand.Next(50, 61);

var myNum = rand.Next(0, 2) == 1 ? num1 : num2;
2
  • Thank you, your method is wonderful. but can I use this method for taking random numbers from 3 groups or even more? Commented Nov 13, 2015 at 12:31
  • Yes, it could be extended to support any number of groups. I think the basic example is good though because it's easy to understand and answers your question.
    – Sean
    Commented Nov 16, 2015 at 22:48
2

You are generating 22 distinct random numbers, 10-20 and 50-60. So do that first:

int randomNumber = rnd.Next(0, 22);

Now, you have random numbers from 0 to 21.

Add ten:

randomNumber += 10;

Now, you have random numbers between from 10 to 31.

Add 29 for all numbers >= 21:

if (randomNumber >= 21) {
    randomNumber += 29;
}

Now, you have random numbers from 10 to 20, and from 50 to 60.

1
  • Tip: you don't have to specify the lower bound when it is 0. So rnd.Next(22); would also do it. Commented Nov 12, 2015 at 21:37
2

A more general approach would be to make an Extension Method for the Random class in which you add NextFromRanges and NextDoubleFromRanges methods. So it will work for any given number of ranges of any type.
First you need to define a Range class. Make it generic so you can reuse it for different types, not only for example for int ranges but also for double.

/// <summary>The Range class.</summary>
/// <typeparam name="T">Generic parameter.</typeparam>
public class Range<T>
{
    /// <summary>Minimum value of the range.</summary>
    public T Minimum { get; set; }

    /// <summary>Maximum value of the range.</summary>
    public T Maximum { get; set; }

    public Range(T min, T max)
    {
        Minimum = min;
        Maximum = max;
    }
}

public static class RandomExtension
{
    static Random random = new Random();

    public static int NextFromRanges(this Random random, List<Range<int>> ranges)
    {
        int randomRange = random.Next(0, ranges.Count);
        return random.Next(ranges[randomRange].Minimum, ranges[randomRange].Maximum);
    }

    public static double NextDoubleFromRanges(this Random random, List<Range<double>> ranges)
    {
        int randomRange = random.Next(0, ranges.Count);
        double doubleNrRange = ranges[randomRange].Maximum - ranges[randomRange].Minimum;
        return ranges[randomRange].Minimum + random.NextDouble()*doubleNrRange;
    }
}

And then you can use it like this:

    //instantiate a Random generator
    Random random = new Random();

    //define three integer ranges
    List<Range<int>> intRanges = new List<Range<int>>();
    intRanges.Add(new Range<int>(0, 10));
    intRanges.Add(new Range<int>(50, 60));
    intRanges.Add(new Range<int>(100, 110));

    //define three double ranges
    List<Range<double>> doubleRanges = new List<Range<double>>();
    doubleRanges.Add(new Range<double>(0, 5.5));
    doubleRanges.Add(new Range<double>(50, 55.5));
    doubleRanges.Add(new Range<double>(100, 105.5));

    //generate a random number between one of above three ranges
    //it is shown in the Visual Studio - Output window (Ctrl-W,O)
    Console.WriteLine(random.NextFromRanges(intRanges));
    Console.WriteLine(random.NextDoubleFromRanges(doubleRanges));

It will produce:
-random int number between one of the three given int ranges: 0-10, 50-60 and 100-110.
-random double number between one of the three given double ranges: 0-5.5, 50-55.5, 100-105.5

Just like the Next and NextDouble methods the upperbound is exclusive.

You'll now have two extra methods added to the standard Random class: enter image description here

-2

You could write your own Random class. Where you rewrite the Next method with a new overload that would accept an even number of arguments.

It would look something like:

Random.NextFromGroups(10, 20, 50, 60, 100, 110);

Where the number-pairs mean the ranges.

Signature:

int NextFromGroups(params int[]);

and it would throw an Exception when it gets an odd number of arguments.

Not the answer you're looking for? Browse other questions tagged or ask your own question.