3

I have 8 labels. I want each label to have its text property set to a random number. For some reason only the first label is having a number set, why is this? (Also, although not directly related, if there's a better way of doing label1.Text, label2.Text, label3.Text etc, please let me know!)

Thanks

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        go();
    }

    void go()
    {
        int[] numbers = new int[8];

        foreach (int number in numbers) 
        {
            numbers[number] = getRandomNumber();
        }

        label1.Text = numbers[0].ToString();
        label2.Text = numbers[1].ToString();
        label3.Text = numbers[2].ToString();
        label4.Text = numbers[3].ToString();
        label5.Text = numbers[4].ToString();
        label6.Text = numbers[5].ToString();
        label7.Text = numbers[6].ToString();
        label8.Text = numbers[7].ToString();
    }

    int getRandomNumber()
    {
        Random random = new Random();
        return random.Next(10, 1000);
    }
}
jskidd3
  • 4,609
  • 15
  • 63
  • 127
  • Make random static and outside of your function. – Prix Aug 06 '13 at 22:11
  • 2
    your problem is that the same number is being generated for all the 8 labels ? or that only the first label shows a value and all the other 7 dont show any number ? – Mauricio Gracia Gutierrez Aug 06 '13 at 22:15
  • @AustinSalonen This is not a duplicate. As found in the answers, the Random object was not the full cause of the problem. All the other labels were still being assigned 0, it was the foreach loop that was the main problem. – jskidd3 Aug 07 '13 at 09:38

4 Answers4

6

Edit: More problems

only the first label is having a number set

The reason for this is that you have declared and initalized an int[] in this way:

int[] numbers = new int[8];

After this you have an array with Length 8 but all ints are default(int) what is 0.

Therefore the following foreach loop ...

foreach (int number in numbers) 
{
    numbers[number] = getRandomNumber();
}

... will only initialize the first int to a random number(well, not really random, more about this later). You could use a for-loop instead:

for (int iii=0; iii<numbers.Length;iii++)
{ 
    numbers[iii] = getRandomNumber();
}

But if you use my improved code below that will also solve this issue.


Use the same random instance in the loop. Otherwise it will create the same number since it's seeded with the current time.

MSDN:

The random number generation starts from a seed value. If the same seed is used repeatedly, the same series of numbers is generated. One way to produce different sequences is to make the seed value time-dependent, thereby producing a different series with each new instance of Random. By default, the parameterless constructor of the Random class uses the system clock to generate its seed value, while its parameterized constructor can take an Int32 value based on the number of ticks in the current time.

Random rnd = new Random();
foreach (int number in numbers) 
{
    numbers[number] = rnd.Next(10, 1000);
}

According to your second question how to improve the code: you could use an array with your labels:

Random random = new Random();
var labels = new[] { label1, label2, label3, label4, label5, label6, label7, label8 };
for (int i = 0; i < labels.Length; i++)
{
    labels[i].Text = random.Next(10, 1000).ToString();
}
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • Thanks for your answer! As a newb, would you mind me asking why the 'var' datatype is used? Is this like an implicit declaration? If the label is an object, would it not be better to make an array of objects? – jskidd3 Aug 06 '13 at 22:27
  • 1
    @JoelKidd: [`var`](http://msdn.microsoft.com/en-us/library/bb383973.aspx) is not a real datatype. It is a replacement for the actual type. So it's still strongly typed (as opposed to `dynamic`) but it's shorter than `Label[]`. So if the type is obvious because i make the assignement i use `var`, just to prevent horizontal scrolling and don't repeat myself. If the type is not obvious i don't use `var` but the actual type, since readability is more important than conciseness. However, in this case it would have been better to use `Label[]` ;-) – Tim Schmelter Aug 06 '13 at 22:31
  • Thanks very much for the detailed explanation. I'm normally writing JavaScript so you can understand the confusion, having everything strongly-typed is new to me so I thought I'd better ask :P – jskidd3 Aug 06 '13 at 22:39
  • @Tim the issue wasn't that the label text wasn't random. He hadn't gotten that far yet. He wasn't getting any text to be anything other than blank. In your first solution, `numbers[number]` is what was causing the problem that he experienced. – ShadowCat7 Aug 06 '13 at 23:43
  • @ShadowCat7 + Derek: You're right. Thanks for the note. I've edited my answer accordingly. – Tim Schmelter Aug 06 '13 at 23:55
  • Thanks for making the edit. Loved your approach for setting the `Text` value for each `Label`. Great answer. – Derek W Aug 07 '13 at 00:18
  • I keep trying to edit the title for this question to reflect the posed problem, but it keeps getting rejected. @Tim since you originally edited it, can you suggest reverting it? – ShadowCat7 Aug 07 '13 at 01:07
  • Hi @ShadowCat7, what do you recommend I change it to? (It wasn't me rejecting your request to edit the title) – jskidd3 Aug 07 '13 at 09:17
5

The problem is in your foreach loop. You are using number as the index, when it is really the value at the index in the array. The effect is that only the first label.Text will have a value! Also, since you are creating a new Random every time, Random.Next will return the same value because random seeds are based on time. Try this instead:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        go();
    }

    void go()
    {
        int[] numbers = new int[8];

        Random random = new Random();

        for (int i = 0; i < 8; i++)
        {
            numbers[i] = random.Next(10, 1000);
        }

        label1.Text = numbers[0].ToString();
        label2.Text = numbers[1].ToString();
        label3.Text = numbers[2].ToString();
        label4.Text = numbers[3].ToString();
        label5.Text = numbers[4].ToString();
        label6.Text = numbers[5].ToString();
        label7.Text = numbers[6].ToString();
        label8.Text = numbers[7].ToString();
    }
}
Ehsan88
  • 3,569
  • 5
  • 29
  • 52
ShadowCat7
  • 804
  • 8
  • 16
1

It's because of

int getRandomNumber()
{
    Random random = new Random(); // <-- This line
    return random.Next(10, 1000);
}

Do this instead:

private static readonly Random random = new Random(); // <-- only set once

int getRandomNumber()
{
    return random.Next(10, 1000);
}

What's happening in the first one is that you're seeding it with the same value over and over again since time hasn't technically ticked if the loop is too tight. In the second one what I'm doing is seeding the generator once - thus getting a different number every time.

McAden
  • 13,714
  • 5
  • 37
  • 63
0

As ShadowCat7 pointed out, the core problem here is not that Random is being misused, but that the foreach loop is being misused.

The following the line of code.

int[] numbers = new int[8];

Declares an array of 8 int's all at the value of 0.

Hence, when you execute the following foreach loop.

foreach (int number in numbers) 
{
    numbers[number] = getRandomNumber();
}

You are iterating through each int value contained in the array of integers called numbers which as previously stated are all 0! Thus, when you use it as the argument in the array indexing operator [] you are repeatedly making this call.

numbers[0] = getRandomNumber();

Which is the real reason why you are not seeing the rest of your array populated with a pseudo-random number between 10 and 1000.

While it is true that continually creating a new instance of Random will generate the same number for you over and over again by reusing the same seed (defeating the purpose of using Random in a loop like this), the chief issue here of why 7 of your 8 labels are 0 is because of the misuse of the foreach loop.

As for a clever way of setting the Text value for each Label, see Tim Schmelter's answer as it is brilliant.

Derek W
  • 9,708
  • 5
  • 58
  • 67