Adding random values from array with some probability - c#

Let's say I have a code for a windows form, that generates greetings when you press a button.
string[] Greetings = new string[] { "Hi", "Hello", "Howdy!", "Hey" };
string[] Smilies = new string[] {";)", ":)", "=)", ":-)" };
Random rand = new Random();
string Greet = Greetings[rand.Next(0, Greetings.Length)];
string Smile = Smilies[rand.Next(0, Smilies.Length)];
TextBox.Text = Greet + " " + Smile;
Clipboard.SetText(TextBox.Text);
What if I want to add smilies with a probability of X%. So that they do not appear all the time, but with a chance I set in the code? What is a good way to do it?
I thought of something like this --
public void chance (string source, int probability)
{
Random chanceStorage = new Random();
if (probability >= chanceStorage.Next(0, 100))
TextBox.Text = source;
}
And then
TextBox.Text = Greet;
chance("_" + Smile, X);
Is that optimal?

50% chance to smile:
string[] Greetings = new string[] { "Hi", "Hello", "Howdy!", "Hey" };
string[] Smilies = new string[] {";)", ":)", "=)", ":-)" };
Random rand = new Random();
string Greet = Greetings[rand.Next(0, Greetings.Length)];
string Smile = rand.NextDouble() > 0.5 ? " "+Smilies[rand.Next(0, Smilies.Length)] : string.Empty;
TextBox.Text = Greet + Smile;

I'd simply generate a random double between 0, 1 (inclusive of 0 only) with random.NextDouble(). Then you can just check that a probability (as a value between 0 and 1) is less than the generated number.
For example
double chance = 0.35; //35%
bool createSmiley = rand.NextDouble() < chance;
This is not necessarily exactly precise (because of the finite precision of floating point numbers) but will get you very close. And allows for more precision than just using ints as your random numbers.
A demo of the random generation of smileys.
On another note, I'd refactor your code a bit to better isolate the logic. I'd personally just try to manipulate a single string, and set the .Text property once after all the string processing is done.

I would divide the length of your Smilies array by your probability to give a range of random numbers to generate.
4 smilies / 25% probablity = 16. So your random generator would generate a random number from 0 - 15 giving a 25% chance of using a smiley. If the generated number is outsides the bounds of the array, don't use a smiley.
using System;
public class Program
{
public static void Main()
{
Random rand = new Random();
double percentage = rand.NextDouble();
string[] greetings = new[] { "Hi", "Hello", "Howdy!", "Hey" };
string[] smilies = new[] { ";)", ":)", "=)", ":-)" };
// Get a greeting
string greet = greetings[rand.Next(0, greetings.Length)];
// Generate the smiley index using the probablity percentage
int randomIndex = rand.Next(0, (int)(smilies.Length / percentage));
// Get a smiley if the generated index is within the bound of the smilies array
string smile = randomIndex < smilies.Length ? smilies[randomIndex] : String.Empty;
Console.WriteLine("{0} {1}", greet, smile);
}
}
See working example here... https://dotnetfiddle.net/lmN5aP

Related

How do I convert a value from Random to a string?

I'm new to c# and I would like to use a value that a random method would give me from an actual array list. But I can't seem to convert it or use a console.readline() on it. Here goes my code.
static void Main(string[] args)
{
string[] mots = new string[] { "pomme", "animal", "pont", "ensemble", "visuel", "acronyme", "cellule", "article", "syllable", "programme" };
Random mot = new Random(mot.GetHashCode());
mot = Console.ReadLine();
Console.WriteLine(mots[mot.Next(9)]);
string mot = "pomme";
char[] charArray = mot.ToCharArray();
Array.IndexOf(charArray);
}
How do I convert the output into a string in order to use it afterwards? Thank you.
To get and output to the console a random element from the mots array:
var mots = new [] { "pomme", "animal", "pont", "ensemble", "visuel", "acronyme", "cellule", "article", "syllable", "programme" };
var rand = new Random();
var index = rand.Next(0, mots.Length); // returns a random int between 0 and mots.Length - 1 (see below)
var mot = mots[index];
var motString = mot.ToString(); // get the string value
Console.WriteLine("Random element: {0}. String value: {1}.", mot, motString);
From the Microsoft Random.Next documentation
The Next(Int32, Int32) overload returns random integers that range from minValue to maxValue – 1. However, if maxValue equals minValue, the method returns minValue.
Try it with the index. Create a random value with max value of the array length - 1. Then return the string at this random index.
string[] mots = new string[] { "pomme", "animal", "pont", "ensemble", "visuel", "acronyme", "cellule", "article", "syllable", "programme" };
Random Rnd = new Random();
string RandomString()
{
return mots[Rnd.Next(0, mots.Length - 1)];
}
Hope this helps. Feel free to ask.

Get a range from two integers

string num = db.SelectNums(id);
string[] numArr = num.Split('-').ToArray();
string num contain for an example "48030-48039";
string[] numArr will therefor contain (48030, 48039).
Now I have two elements, a high and low. I now need to get ALL the numbers from 48030 to 48039. The issue is that it has to be string since there will be telephone numbers with leading zeroes now and then.
Thats why I cannot use Enumerable.Range().ToArray() for this.
Any suggestions? The expected result should be 48030, 48031, 48032, ... , 48039
This should work with your leading zero requirement:
string num = db.SelectNums(id);
string[] split = num.Split('-');
long start = long.Parse(split[0]);
long end = long.Parse(split[1]);
bool includeLeadingZero = split[0].StartsWith("0");
List<string> results = new List<string>();
for(int i = start; i <= end; i++)
{
string result = includeLeadingZero ? "0" : "";
result += i.ToString();
results.Add(result);
}
string[] arrayResults = results.ToArray();
A few things to note:
It assumes your input will be 2 valid integers split by a single hyphen
I am giving you a string array result, personally I would prefer to work with a List<int> in the end
If the first number contains a single leading zero, then all results will contain a single leading zero
It uses long to cater for longer numbers, beware that the max number that will parse is 9,223,372,036,854,775,807, you could double this value (not length) by using ulong
Are you saying this?
int[] nums = new int[numArr.Length];
for (int i = 0; i < numArr.Length; i++)
{
nums[i] = Convert.ToInt32(numArr[i]);
}
Array.Sort(nums);
for (int n = nums[0]; n <= nums[nums.Length - 1]; n++)
{
Console.WriteLine(n);
}
here link
I am expecting your string always have valid two integers, so using Parse instead TryParse
string[] strList = "48030-48039".Split('-').ToArray();
var lst = strList.Select(int.Parse).ToList();
var min = lst.OrderBy(l => l).FirstOrDefault();
var max = lst.OrderByDescending(l => l).FirstOrDefault();
var diff = max - min;
//adding 1 here otherwise 48039 will not be there
var rng = Enumerable.Range(min,diff+1);
If you expecting invalid string
var num = 0;
var lst = (from s in strList where int.TryParse(s, out num) select num).ToList();
This is one way to do it:
public static string[] RangeTest()
{
Boolean leadingZero = false;
string num = "048030-48039"; //db.SelectNums(id);
if (num.StartsWith("0"))
leadingZero = true;
int min = int.Parse(num.Split('-').Min());
int count = int.Parse(num.Split('-').Max()) - min;
if (leadingZero)
return Enumerable.Range(min, count).Select(x => "0" + x.ToString()).ToArray();
else
return Enumerable.Range(min, count).Select(x => "" + x.ToString()).ToArray(); ;
}
You can use string.Format to ensure numbers are formatted with leading zeros. That will make the method work with arbitrary number of leading zeros.
private static string CreateRange(string num)
{
var tokens = num.Split('-').Select(s => s.Trim()).ToArray();
// use UInt64 to allow huge numbers
var start = UInt64.Parse(tokens[0]);
var end = UInt64.Parse(tokens[1]);
// if your start number is '000123', this will create
// a format string with 6 zeros ('000000')
var format = new string('0', tokens[0].Length);
// use StringBuilder to make GC happy.
// (if only there was a Enumerable.Range<ulong> overload...)
var sb = new StringBuilder();
for (var i = start; i <= end; i++)
{
// format ensures that your numbers are padded properly
sb.Append(i.ToString(format));
sb.Append(", ");
}
// trim trailing comma after the last element
if (sb.Length >= 2) sb.Length -= 2;
return sb.ToString();
}
Usage example:
// prints 0000012, 0000013, 0000014
Console.WriteLine( CreateRange("0000012-0000014") );
Three significant issues were brought up in comments:
The phone numbers have enough digits to exceed Int32.MaxValue so
converting to int isn't viable.
The phone numbers can have leading zeros (presumeably for some
international calling?)
The possible range of numbers can theoretically exceed the maximum size of an array (which may have memory issues, and I think may not be represented as a string)
As such, you may need to use long instead of int, and I would suggest using deferred execution if needed for very large ranges.
public static IEnumerable<string> EnumeratePhoneNumbers(string fromAndTo)
{
var split = fromAndTo.Split('-');
return EnumeratePhoneNumbers(split[0], split[1]);
}
public static IEnumerable<string> EnumeratePhoneNumbers(string fromString, string toString)
{
long from = long.Parse(fromString);
long to = long.Parse(toString);
int totalNumberLength = fromString.Length;
for (long phoneNumber = from; phoneNumber <= to; phoneNumber++)
{
yield return phoneNumber.ToString().PadLeft(totalNumberLength, '0');
}
}
This assumes that the padded zeros are already included in the lower bound fromString text. It will iterate and yield out numbers as you need them. This can be useful if you're churning out a lot of numbers and don't need to fill up memory with them, or if you just need the first 10 or 100. For example:
var first100Numbers =
EnumeratePhoneNumbers("0018155500-7018155510")
.Take(100)
.ToArray();
Normally that range would produce 7 billion results which cannot be stored in an array, and might run into memory issues (I'm not even sure if it can be stored in a string); by using deferred execution, you only create the 100 needed.
If you do have a small range, you can still join up your results into a string as you desired:
string numberRanges = String.Join(", ", EnumeratePhoneNumbers("0018155500-0018155510"));
And naturally you can put this array creation into your own helper method:
public static string GetPhoneNumbersListing(string fromAndTo)
{
return String.Join(", ", EnumeratePhoneNumbers("0018155500-0018155510"));
}
So your usage would be:
string numberRanges = GetPhoneNumbersListing("0018155500-0018155510");
A complete solution inspired by the answer by #Dan-o:
Inputs:
Start: 48030
End: 48039
Digits: 6
Expected String Output:
048030, 048031, 048032, 048033, 048034, 048035, 048036, 048037, 048038, 048039
Program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class Program
{
public static void Main()
{
int first = 48030;
int last = 48039;
int digits = 6;
Console.WriteLine(CreateRange(first, last, digits));
}
public static string CreateRange(int first, int last, int numDigits)
{
string separator = ", ";
var sb = new StringBuilder();
sb.Append(first.ToString().PadLeft(numDigits, '0'));
foreach (int num in Enumerable.Range(first + 1, last - first))
{
sb.Append(separator + num.ToString().PadLeft(numDigits, '0'));
}
return sb.ToString();
}
}
For Each item In Enumerable.Range(min, count).ToArray()
something = item.PadLeft(5, "0")
Next

Generate random 6 digit number

I've been searching for a couple of hours and I just can't seem to find a answer to this question. I want to generate a random number with 6 digits. Some of you might tell me to use this code:
Random generator = new Random();
int r = generator.Next(100000, 1000000);
But that limits my 6 digits to all be above 100 000 in value. I want to be able to generate a int with 000 001, 000 002 etc. I later want to convert this integer to a string.
If you want a string to lead with zeroes, try this. You cannot get an int like 001.
Random generator = new Random();
String r = generator.Next(0, 1000000).ToString("D6");
You want to have a string:
Random r = new Random();
var x = r.Next(0, 1000000);
string s = x.ToString("000000");
For example,
x = "2124"
s = "002124"
As stated in a comment, a "six digit number" is a string. Here's how you generate a number from 0-999999, then format it like "000482":
Random r = new Random();
int randNum = r.Next(1000000);
string sixDigitNumber = randNum.ToString("D6");
private static string _numbers = "0123456789";
Random random = new Random();
private void DoWork()
{
StringBuilder builder = new StringBuilder(6);
string numberAsString = "";
int numberAsNumber = 0;
for (var i = 0; i < 6; i++)
{
builder.Append(_numbers[random.Next(0, _numbers.Length)]);
}
numberAsString = builder.ToString();
numberAsNumber = int.Parse(numberAsString);
}
I agree with the comment above that 000 001 can't be an integer, but can be a string with:
Random generator = new Random();
int r = generator.Next(1, 1000000);
string s = r.ToString().PadLeft(6, '0');
string s = generator.Next(0, 1000000).ToString("D6");
or
string s = generator.Next(0, 1000000).ToString("000000");
This is a better solution, because it gives you more random numbers and is not based on the system clock.
Cryptographic random number generators create cryptographically strong random values.
System.Security.Cryptography.RandomNumberGenerator.GetInt32(0, 1000000);
To ensure that the resulting value has six digits, you can convert to string and append zeros at the start. e.g GeneratedValue.ToString().Padleft(6,'0') using Matt's method above.
See official documentation for additional details.
solutions that use
Random generator = new Random();
int r = generator.Next(1, 1000000);
dont seem to work always.
I am calling the following method in a class constructor and it gives same number after the first time.
internal string GenerateID()
{
Random r = new Random();
int randNum = r.Next(1000000);
string sixDigitNumber = randNum.ToString("D6");
return sixDigitNumber;
}
Attached is image of the debug statement in .net unitTest for the class.
My project is .net 4.8.
I have moved to using System.Security.Cryptography.RandomNumberGenerator as suggested above.

Replace word/value in text with dynamic number

For ex. I have string
string text = #"Today is {Rand_num 15-22} day. {Rand_num 11-55} number of our trip.";
I need to replace every Rand_num constraction with rand number (between stated numbers 15-22 or 11-55)
Tried smth but don't know what to do next
string text = #"Today is {Rand_num 15-22} day. {Rand_num 11-55} number of our trip.";
if (text.Contains("Rand_num"))
{
string groups1 = Regex.Match(text, #"{Rand_num (.+?)-(.+?)}").Groups[1].Value;
string groups2 = Regex.Match(text, #"{Rand_num (.+?)-(.+?)}").Groups[2].Value;
}
How about:
Random rand = new Random();
text = Regex.Replace(text, #"{Rand_num (.+?)-(.+?)}", match => {
int from = int.Parse(match.Groups[1].Value),
to = int.Parse(match.Groups[2].Value);
// note end is exclusive
return rand.Next(from, to + 1).ToString();
});
Obviously output will vary, but I get:
Today is 21 day. 25 number of our trip.
You can use Random Method, Check the Code Snippet if it suites you.
Random random=new Random();
string text=String.Format("Today is {0} day. {1} number of our trip.", random(15-22), random(11-15));

How to generate string based on Pattern

I have a case where I have to generate transaction number based on specific pattern
The pattern is following:
MA 0000000/dd/mm/YYYY/00000
where first zeros are random numbers then current date and last zeros should be incremental
(00001... 00010... 00100... 00578)
Could you please provide correct way to implement this case.
public static class Generator
{
static int current = 0;
static Random rand = new Random();
public static string NextId()
{
return string.Format("MA {0:0000000}/{1}/{2:00000}",
rand.Next() % 100000,
DateTime.Now.ToString("dd/MM/yyyy"),
current++ );
}
}
public string NextId(int lastCount)
{
var rand = new Random();
return string.Format("MA{0:0000000}/{1}/{2:00000}",
rand.Next(9999999),
DateTime.Today.ToString("dd/MM/yyyy"),
lastCount + 1);
}
Random rand = new Random();
int randomNumber = rand.Next(100000000);
int counter = 1;
string str = "MA" + randomNumber.ToString() + DateTime.Now.ToString("/dd/MM/yyyy/") + counter.ToString("X4");
Console.WriteLine(str);
Probably you are concerned about two things:
DateTime format: you may use: DateTime.Now.ToString("/dd/MM/yyyy/")
and
Padding leading zeros to a number, you may use:
counter.ToString("X4")
Also see: How to: Pad a Number with Leading Zeros
Random rand = new Random();
string random = rand.Next(10000000).ToString("D7");
string date = DateTime.Today.ToString("dd/MM/yyyy");
string increment = inc.ToString("D5");
String.Format("MA {0}/{1}/{2}", random, date, increment);
Where inc is the incremental number. You should know this, or otherwise find out what the next number should be.
for(int i=0;i<n;i++)
{
Console.WriteLine("MA "+(new Random()).Next(0,100).ToString("D7")+DateTime.Now.ToString("dd/MM/yyyy")+ i.ToString("D5"));
}
Where Next() generates random number between 0 and 100
i.ToString("D5") will give you number in 00001.. format

Categories

Resources