Random with a specific amount of a specific value - c#

my problem is following: I need to create some random values for scheduling. For example process times are given. Lets say a job j on a machine i gets a random value between (1,99). thats the time the jobs needs on this machine.
Now, I need to manipulate this random values. I like to say of all random process times, 20% of them are zero process times. So does anybody know how it is possible to give an array with integers a specific amount with a specific time??
here the normal random:
p_machine_job_completionTime = new int[Constants.numberMachines][];
for (i = 0; i < Constants.numberMachines; i++)
{
p_machine_job_completionTime[i] = new int[Constants.numberJobs];
for (j = 0; j < Constants.numberJobs; j++)
{
p_machine_job_completionTime[i][j] = random.Next(1, 99);
}
}
Now, jobs may skip a machine and consequently have a processing time of 0. Is it possible to limit the random values, with guaranteeing that x% of all my random values has the value 0 ??
e.g.:
20% of p_machine_job_completionTime[i][j] = 0
80% of p_machine_job_completionTIme[i][j] = random (1,99)
I am very thankful for any small any tiny advice.

Just separate two cases: 20% when 0 should be returned and 80% when 1..99 is the outcome
Random random;
...
int value = random.Next(5) == 0 ? 0 : random.Next(99) + 1;

One way to do this would be by generating two random values: One for determining whether to use 0, and (possibly) another to generate non-zero values. However, you can combine both randoms into one by increasing the range of your random values by the appropriate amount, and converting any results above your limit to 0:
int val = random.Next(1, 123);
if (val >= 99)
val = 0;
In this case, your target range contains 98 possible values (1 to 98, since the upper bound is exclusive). To get 0 with 20% probability, you need to extend the range of your random generator to 1 / (1 - 20%), or 125% of its present value, which would be 123.

I think what the existing answers are missing is this important point:
"Is it possible to limit the random values, with guaranteeing that x%
of all my random values has the value 0"
If you need to guarantee that at the end of the day some random exactly x% of the items are given a value of zero, then you can't use random as in the answer from #Douglas. As #Douglas says, "To get 0 with 20% probability." But as stated in the question we don't want 20% probability, we want EXACTLY 20%, and the other exactly 80% to have random values. I think the code below does what you want. Filled in some values for numberMachines and numberJobs so the code can be run.
int numberMachines = 5;
int numberJobs = 20;
Random random = new Random();
var p_machine_job_completionTime = new int[numberMachines][];
var theTwentyPercent = new HashSet<int>(Enumerable.Range(0,(numberJobs * numberMachines) -1 ).OrderBy(x => Guid.NewGuid()).Take(Convert.ToInt32((numberMachines * numberJobs) * 0.2)));
for (int i = 0; i < numberMachines; i++) {
p_machine_job_completionTime[i] = new int[numberJobs];
for (int j = 0; j < numberJobs; j++) {
int index = (i * numberJobs) + j;
if (theTwentyPercent.Contains(index)) {
p_machine_job_completionTime[i][j] = 0;
}
else {
p_machine_job_completionTime[i][j] = random.Next(1, 99);
}
}
}
Debug.Assert( p_machine_job_completionTime.SelectMany(x => x).Count(val => val==0) == (numberMachines * numberJobs) * 0.2 );

I think that you do not need to include this within Random in your case. You could simply use modulo as a part of your for loop:
p_machine_job_completionTime = new int[Constants.numberMachines][];
int counter = 0;
for (i = 0; i < Constants.numberMachines; i++)
{
p_machine_job_completionTime[i] = new int[Constants.numberJobs];
for (j = 0; j < Constants.numberJobs; j++)
{
if( counter%5 == 0)
{
p_machine_job_completionTime[i][j] = 0;
}
else
{
p_machine_job_completionTIme[i][j] = random (1,99);
}
counter++;
}
}

Related

Using specific array count

My array max size is 20. If I were to enter data that would be less than 20,how do I get it where my program only counts the used arrays?
for (int i = 0; i < Score.Length; i++)
{
sum = sum + Score[i];
}
average = sum / Score.Length;
If I use this for loop above, it always divides by 20 for the average. I need it to only count the ones I entered, not 20. I would prefer solutions using arrays
If you insist in using arrays, then you must keep track of how many items you added to the array, like:
int[] Score = new int[20];
Random rdn = new Random();
int size=0;
for(int i=0;i<rdn.Next(0,20);i++)
{
Score[i] = rdn.Next();
size++;
}
int sum = 0;
for (int i = 0; i < size; i++)
{
sum = sum + Score[i];
}
double average = sum / size;
A better option is to use the List class that keep track for you of the number of items you add
List<int> Score = new List<int>();
Random rdn = new Random();
for(int i=0;i<rdn.Next(0,20);i++)
{
Score.Add(rdn.Next());
}
int sum = 0;
for (int i = 0; i < Score.Count; i++)
{
sum = sum + Score[i];
}
double average = sum / Score.Count;
And of course, as you didn't say the type of your data you could use other data types, like double, float, long, decimal for both solutions.
That is probably an overkill, but another approach would be to use a SparseVector class of the Math.Numerics package:
Sparse Vector uses two arrays which are usually much shorter than the vector. One array stores all values that are not zero, the other stores their indices.
PM > Install-Package MathNet.Numerics
var vector = SparseVector.Build.SparseOfArray(Score);
var sum = vector.Sum();
Sum() will only go through non-empty elements.
You need to keep track of the record that are != 0, so
int count = 0;
for(int i = 0; i < array.Length; i++)
{
if ( array[i] != 0 )
{
count++;
sum += array[i];
}
}
average = sum / count;
And beware of division by 0 ;)

time to get in array of bitarrays

I have a problem that I don't understand, in that code:
ilProbekUcz= valuesUcz.Count; //valuesUcz is the list of <float[]>
for (int i = 0; i < ilWezlowDanych; i++) nodesValueArrayUcz[i] = new BitArray(ilProbekUcz);
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < ilProbekUcz; i++)
{
int index = 0;
linia = (float[])valuesUcz[i];//removing this line not solve problem
for (int a = 0; a < ileRazem; a++)
for (int b = 0; b < ileRazem; b++)
if (a != b)
{
bool value = linia[a] >= linia[b];
nodesValueArrayUcz[index][i] = value;
nodesValueArrayUcz[ilWezlowDanychP2 + index][i] = !value;
index++;
}
}
sw.Stop();
When i increase size of valuesUcz 2x, time of execution is 4x bigger
When i increase size of valuesUcz 4x, time of execution is 8x bigger
etc ...
(ileRazem,ilWezlowDanych is the same)
I understand: increase of ilProbekUcz increases size of BitArrays but i test it many times and it is no problem - time should grow linearly - in code:
ilProbekUcz= valuesUcz.Count; //valuesTest is the list of float[]
for (int i = 0; i < ilWezlowDanych; i++) nodesValueArrayUcz[i] = new BitArray(ilProbekUcz);
BitArray test1 = nodesValueArrayUcz[10];
BitArray test2 = nodesValueArrayUcz[20];
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < ilProbekUcz; i++)
{
int index = 0;
linia = (float[])valuesUcz[i];//removing this line not solve problem
for (int a = 0; a < ileRazem; a++)
for (int b = 0; b < ileRazem; b++)
if (a != b)
{
bool value = linia[a] >= linia[b];
test1[i] = value;
test2[i] = !value;
index++;
}
}
time grows linearly, so the problem is to take a BitArray from the array...
Is any method to do it faster ? (i want time to grow linearly)
You have to understand that measuring time there are many factors that makes them inacurate. The biggest factor when you have huuuuuge arrays as in your example is cashe misses. Many times the same thing written when taking account of cashe, can be as much as 2-5 or more times faster. Two words how cashe works, very roughly. Cache is memory inside cpu. It is waaaaaaaaaaaaaay faster than ram so when you want to fetch a variable from memory you want to make sure this variable is stored in cache and not in ram. If it is stored in cache we say we have a hit otherwise a miss. Some times, not so often, a program is so big that it stores variables in hard drive. In that case you have a huuuuuuuuuuuge hit in delay when you fetch these! An example of cache:
Lets say we have an array of 10 elements in memory(ram)
when you get the first element testArray[0], because testArray[0] is not in cache the cpu brings this value along with a number(lets say 3, the number depends on the cpu) of adjacent elements of the array eg it stores to cache testArray[0], testArray[1], testArray[2], testArray[3]
Now when we get testArray[1] it is in cache so we have a hit. The same with testArray[2] and testArray[3]. testArray[4] isn't in cache so it gets testArray[4] along with another 3 testArray[5], testArray[6], testArray[7]
and so on...
Cache misses are very costly. That means you may expect an array of double the size is going to be accessible double the time. But this is not true. Bigger arrays more misses
and the time may increase 2 or 3 or 4 or more times from what you expect. This is normal. In your example that is what is happening. From 100 million elemensts(first array) you go t0 400 million (second one). The missesare not double but waaay more as you saw. A very cool trick has to do with the way you access an array. In your example ba1[j][i] = (j % 2) == 0; is way worse than ba1[i][j] = (j % 2) == 0;. The same with ba2[j][i] = (j % 2) == 0; and ba1[i][j] = (j % 2) == 0;. You can test it. Just reverse i and j. It has to do with the way the 2D array is stored in memory so in the second case you have more hits that the first one.

Generating an array of numbers based off the smallest numbers in other arrays?

How do I go about making an array of numbers based off of the lowest values generated in other arrays? I have made an array that generates numbers between -1000 and 1000 and calculates the the lowest number from that; my problem comes after that I believe. I cant figure out how to add the lowest value to the "lowestNumbers" array.
static void Main(string[] args)
{
//ints and arrays used in the program.
int min = -1000;
int max = 1000;
int currentMinimum = 1000;
int[] numbers = new int[10];
int[] lowestNumbers = new int[numbers.Length];
Random rndm = new Random();
//Using a loop to create random numbers within numbers array between -1000 and 1000.
for (int i = 0; i < lowestNumbers.Length; i++)
{
if (i < lowestNumbers.Length)
{
for (int index = 0; index < numbers.Length; index++)
{
if (index < numbers.Length)
{
numbers[index] = rndm.Next(min, max);
}
}
for (int index = 0; index < numbers.Length; index++)
{
if (numbers[index] < currentMinimum)
currentMinimum = numbers[index];
}
}
lowestNumbers[i] = currentMinimum;
}
foreach (int value in lowestNumbers)
Console.WriteLine(value);
Console.WriteLine("//////////////////////////////////////////////////////////////////////////");
}
}
}
Use the power of Linq:
var numbers = Enumerable.Range(1, 100).Select(_ => rndm.Next(min, max)).ToArray();
var lowest = numbers.Min();
Based off the answer of #Laoujin, but slightly expanded a bit.
This will generate 1000 integers, from -1000 to 1000, and give you an array of the 100 lowest. I added 1 to max in the call to Random.Next(Int32, Int32) since maxValue is exclusive, otherwise the number 1000 would never show up in the resulting array.
var numbers = Enumerable.Range(1, 1000).Select(_ => rndm.Next(min, max+1)).ToArray();
var lowest = numbers.OrderBy(n => n).Take(100).ToArray();
As an extra note, if you are confused about the _ in the first line (many people are, the first time they see it used this way), that is just commonly used to denote an unused argument in a lambda expression. In this case, that variable contains the current number generated from Enumerable.Range() via the Select() call, but since it isn't being used, it is just named _. This isn't enforced by the language in any way, it is a common pattern that lots of programmers use.
That might contain duplicates though, so if you don't want them, you can pass the list though IEnumerable.Distinct() first, which returns only unique items:
var lowest = numbers.Distinct().OrderBy(n => n).Take(100).ToArray();
If you want the absolute lowest number from the first array, you can just do:
var lowestNumber = numbers.Min();

Char in random position

I`m facing with the problem of putting char in random position.
I have a table full of dots and I have to replace 30% of these dots with *
Size: 10x5
I used function Random.
Random rnd = new Random();
if (rnd.Next() % 10 > 3)
Console.Write(". ");
else
Console.Write("* ");
Everything is in 2 loops which hold Length and Height of table (10x5).
But it only makes PROBABILITY of 30% to make * instead of .
It takes good position but every time I start a program there is different amount of *.
It should just have 16 of * (17 - if rounded) every time I start the program
How should I suppose to make 30% always instead of probability?
You have 50 dots. calculate 50*30/100, it becomes 15.
Then generate 15 unique random numbers within range of 0 to 50. those numbers are indexes you have to replace . with *
var indexes = Enumerable.Range(0,50).OrderBy(x => rng.Next()).Take(50*30/100).ToList();
If you are working with 2d index, its fairly easy to convert 1d index into 2d index.
var i = index % 5;
var j = index / 5;
According to what #KonradRudolph said if you don't want to use OrderBy you can check out other ways to shuffle array (or create randomized set) posted here Best way to randomize an array with .NET
Here is more efficient way using Fisher-Yates algorithm that I suggest you to use instead of using OrderBy
var indexes = Enumerable.Range(0, 50).ToArray();
RandomExtensions.Shuffle(rng, indexes);
Write code that does the following:
Declare an array with x * y elements
Populate the entire array with .
Declare a loop with 0.30 * x * y iterations
For each iteration, change a randomly selected element from . to * (you must keep looking until you find one that isn't already a *)
Output the array, x elements per line
Imagine your array to be just 50 elements and forget about the rectangular shape for now. How would you approach that? Declare X dots and 50-X stars, then randomly order them. Like you would randomly order a 1->50 list of numbers.
Now how to randomly order a list of 1->50 numbers? One simple and intuitive way is imagining shuffling cards. Go through the loop and for each position obtain a random number in 1->50. Swap elements chosen (say for i=1 we got random number 7 => swap elements 1 and 7).
Here, you simply need to map this rectangle to those 50 points, which is trivial enough for 2D.
I would randomly select 30% of the possible positions
// create char array
int arrayRows = 5;
int arrayCols = 10;
char[,] arr= new char[arrayRows ,arrayCols];
// populate array with dots
for (int i = 0; i < arrayRows; i++)
{
for (int j = 0; j < arrayCols; j++)
{
arr[i,j] = '.';
}
}
Random rnd = new Random();
int numberOfPossiblePositions = arrayRows * arrayCols;
int k = 0;
while (k < numberOfPossiblePositions * 0.3) {
int position = rnd.Next(numberOfPossiblePositions);
int colIndex = position / 10;
int rowIndex = position % 10;
// if the cell already has * try again
if (arr[rowIndex,colIndex] == '*') {
continue;
}
arr[rowIndex,colIndex] = '*';
k++;
}
Create an array that holds x*y/3 starts and the rest are dots. order by random and iterate through it.
This is the array:
Enumerable.Range(0, count).Select(i => new {Text = "*", Order = rnd.Next() })
.Concat(Enumerable.Range(0, x*y - count)
.Select(i=>new { Text = ".", Order = rnd.Next() }))
.OrderBy(i => i.Order).Select(i=>i.Text).ToList();
And this is the code for iteration:
Random rnd = new Random();
int x = 10;
int y = 5;
int count = x*y/3;
var allPlaces =
Enumerable.Range(0, count).Select(i => new {Text = "*", Order = rnd.Next() })
.Concat(Enumerable.Range(0, x*y - count)
.Select(i=>new { Text = ".", Order = rnd.Next() }))
.OrderBy(i => i.Order).Select(i=>i.Text).ToList();
for (var i = 0; i < x; x++)
{
for (var j = 0; j < y; j++) { Console.Write(allPlaces[i*j + j]); }
Console.WriteLine();
}

What is wrong with my code (it deals with array size)?

I am initializing array size to 1 but I am updating it in the subsequent lines. It is not even storing the first element in the array as the array size is 1 initially but I expected it would. Could someone provide me with an explanation? Here is the code:
class Program
{
static void Main(string[] args)
{
int num = int.Parse(Console.ReadLine());
Console.Write("The binary number for " + num + " is ");
int size = 1;
int[] binary = new int[size];
size = 0;
while(num>=1)
{
if (num % 2 == 0)
binary[size++] = 0;
else
binary[size++] = 1;
//size += 1;
num = num / 2;
}
for (int i = size - 1; i >= 0; i--)
{
Console.Write(binary[i]);
}
Console.WriteLine();
Console.Write("The Compliment of this number is ");
for (int i = size - 1; i >= 0; i--)
{
if (binary[i] == 0)
binary[i] = 1;
else
binary[i] = 0;
}
for (int i = size - 1; i >= 0; i--)
{
Console.Write(binary[i]);
}
Console.WriteLine();
Console.ReadKey();
}
}
You cannot resize an array, it always has the length you gave it to during initialization (1 in your case).
I think the problem is specifically in your expectation that you can update an array size "in the subsequent lines."
When you make the array here:
int[] binary = new int[size];
Then the size is set in stone
When you call something like:
binary[size++] = 0;
This will not actually increase the number of slots in your array. In fact, that code is only changing the index where you are looking to read or write values. I can see that your code is going to quickly go out of bounds of the array (if you ask for anything but binary[0]
It turns out this array is a tricky data type to use; arrays have a fixed size on creation. You want something that can grow!
So you can either:
-Use an array, but declare that it's size is Math.Ciel(logbase2(yourNumber)) to make sure you will have enough space
-Use a data structure that can grow, like a string or list
-You can create a new array every time you need it bigger and assign it like:
binary = new int[++size];
binary[size-1]=whatever
Good luck, hope this helps!

Categories

Resources