I have been trying to create a random string out of alphanumeric characters and to use Do-While Loop to check if the random string meet the requirement. Otherwise, it should continue the Do Loop. However, I found the code I have always generates the same string over and over again. To demonstrate, I set int message_length = 2 and ask While Loop to check if the generated string is "ab" like while (check != "ab").
I have tried to put Random seed = new Random() in the Do Loop, out of the Do Loop, and out of the Main() as you can see the code I commented out. None of them is working. I used Visual Studio 2017, Windows 10 Home. Anyone could help? Many thanks!
(Further comments: Although I got the code working fine now, I still don't understand why the original line check = all_message.ToString(); can interrupt the random number generator in this case. IMHO, the while condition while (check != "ab") is still True so the loop will keep going. But why Random Number Generator stop generating new seed? Anyone could share knowledge about this?
using System;
using System.Text;
using System.Collections.Generic;
public class Program
{
//static Random seed = new Random();
public static void Main(string[] arggs)
{
Random seed = new Random();
const string src = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Console.WriteLine(src.Length);
int string_length = 2;
List<string> all_message = new List<string>();
string check = "";
do
{
//Random seed = new Random();
int i = 0;
StringBuilder message = new StringBuilder();
for (int j = 0; j < string_length; j++)
{
char c = src[seed.Next(0, src.Length)];
message.Append(c);
}
all_message.Add(message.ToString());
check = all_message.ToString();
Console.WriteLine(i + " = " + all_message[i]);
i++;
}
while (check != "ab");
}
}
You are resetting your counter 'i' on every iteration of the loop, so you will always write the first element of the generated list to the console. Initialize i outside the loop.
With the help from others, I figured out the issue. The critical change is check = string.Join("", all_message.ToArray());. With few other minor changes, the solutions is here:
using System;
using System.Text;
using System.Collections.Generic;
public class Program
{
//static Random seed = new Random();
public static void Main(string[] arggs)
{
Random seed = new Random();
const string src = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Console.WriteLine(src.Length);
int string_length = 2;
string check = "";
int i = 0;
do
{
//Random seed = new Random();
List<string> all_message = new List<string>();
StringBuilder message = new StringBuilder();
for (int j = 0; j < string_length; j++)
{
char c = src[seed.Next(0, src.Length)];
message.Append(c);
}
all_message.Add(message.ToString());
check = string.Join("", all_message.ToArray());
//Console.WriteLine(check);
Console.WriteLine(i + " = " + check);
i++;
}
while (check != "ab");
}
}
Hint: Read the comments.
Random seed = new Random();
const string src = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Console.WriteLine(src.Length);
int string_length = 2;
List<string> all_message = new List<string>();
string check = "";
do
{
//Random seed = new Random(); -- you do not need it any more hier.
int i = 0; // if you whant counting with i, put it above the do while.
StringBuilder message = new StringBuilder();
for (int j = 0; j < string_length; j++)
{
char c = src[seed.Next(0, src.Length)];
message.Append(c);
}
all_message.Add(message.ToString());
check = all_message.ToString(); // this is the list from string you do not need it realy and list to string = System.Collections.Generics.List....
//instead check should be equal to all_message[i] case i counting properly
Console.WriteLine(i + " = " + all_message[i]); // and hier simply print the check, you allready have the value.
i++;
}
while (check != "ab");
I ran the following:
Random seed = new Random();
const string src = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Console.WriteLine(src.Length);
int string_length = 2;
List<string> all_message = new List<string>();
string check = "";
int i = 0;
do
{
//Random seed = new Random();
StringBuilder message = new StringBuilder();
for (int j = 0; j < string_length; j++)
{
char c = src[seed.Next(0, src.Length)];
message.Append(c);
}
all_message.Add(message.ToString());
check = all_message.ToString();
Console.WriteLine(i + " = " + all_message[i]);
i++;
}
while (i < 3);
My output was:
62
0 = PQ
1 = xw
2 = he
Note that the index i is initialised outside the loop and so it not reset every time through.
The question then becomes, what are your requirements and when to terminate the loop and what should check be?
Related
I'm making a program that generates the "names" (random lines of text from the ASCII) that are the names of movies in this instance. I should follow them up with a "name" of a director for each (can also be generated from the ASCII), and after that the random year that is the year the "movie" was made (from 1896 to 2021).
I have two separate functions that randomize the names of the movies and directors, but I'm confused with the supposed placement of the Console.Writeline which the intelligence only allows inside their own loops. Otherwise it doesn't seem to be able to use the values "directorname" and "moviename".
I need it to write the names in a single line, ai. (KHGTJ, KGHTJF).
Also I need a way to generate a random year from 1896 to 2021 that is printed after the names of the movie, and director, ai. (KFJU, MDDOS, 1922).
private static void GenerateRandomNames()
{
Random random = new Random();
char y = (char)65;
for (int p = 0; p < 100; p++)
{
string directorname = "";
for (int m = 0; m < 5; m++)
{
int b = random.Next(65, 90);
y = (char)b;
directorname += y;
}
Console.WriteLine(directorname);
}
Random rnd = new Random();
char x = (char)65;
for (int j = 0; j < 100; j++)
{
string moviename = "";
for (int i = 0; i < 5; i++)
{
int a = rnd.Next(65, 90);
x = (char)a;
moviename += x;
}
Console.WriteLine(moviename);
}
Console.WriteLine();
I need to fix the plecement of the Console.Writeline() so it can print both names in the same line, and be able to print the year after them.
I've tried placing the Console.Writeline() outside the loops, but of course it can't then use the name. But this way it prints them the wrong way.
If you want to have minimal changes in your code, you can use the following code:
private static void GenerateRandomNames()
{
//a separate thing for the names of the directors (ASCII)
// then for the years they were made (1896-2021)
//they should all be printed in the end ie. (KGMFK, JDBDJ, 1922)
Random rnd = new Random();
char x = (char)65;
for (int j = 0; j < 100; j++)
{
string directors = "";
string moviename = "";
for (int i = 0; i < 5; i++)
{
int a = rnd.Next(65, 90);
x = (char)a;
moviename += x;
}
for (int i = 0; i < 5; i++)
{
int a = rnd.Next(65, 90);
x = (char)a;
directors += x;
}
Console.WriteLine("( "+directors +", "+ moviename + ", " +rnd.Next(1896, 2021).ToString()+" )");
}
Console.WriteLine();
}
and result:
Not sure if it is good to answer this type of question, but answering it anyway.
Since you only want other 5-letter words and 4-digit numbers ranging from 1896 - 2021,
Just get another variable 'b' and do the same as you did for 'a', like :
int b = rnd.Next(65,90) ;
y = char(b) ;
director name += y ;
and to get the year value, you can use this :
year = rnd.Next(1896,2021)
So, by combining all of the above, you have the code like this :
internal class Program
{
private static void GenerateRandomNames()
{
Random rnd = new Random();
char x = (char)65;
char y = (char) 65 ;
for (int j = 0; j < 100; j++)
{
string moviename = "";
string directorName = "";
int year = rnd.Next(1896,2021);
for (int i = 0; i < 5; i++)
{
int a = rnd.Next(65, 90);
int b = rnd.Next(65, 90);
x = (char)a;
moviename += x;
y = (char)a;
directorName += x;
}
Console.WriteLine(moviename);
Console.WriteLine(directorName);
Console.WriteLine(year);
}
Console.WriteLine();
}
static void Main(string[] args)
{
GenerateRandomNames();
}
}
The task becomes easier if you extract the creation of a random name to a new method. This allows you to call it twice easily. I moved the random object to the class (making it a class field), so that it can be reused in different places.
internal class Program
{
private static readonly Random _rnd = new Random();
private static string CreateRandomName(int minLength, int maxLength)
{
string name = "";
for (int i = 0; i < _rnd.Next(minLength, maxLength + 1); i++)
{
char c = (char)_rnd.Next((int)'A', (int)'Z' + 1);
name += c;
}
return name;
}
private static void WriteRandomNames()
{
for (int i = 0; i < 100; i++)
{
string movie = CreateRandomName(4, 40);
string director = CreateRandomName(3, 30);
int year = _rnd.Next(1896, 2022);
Console.WriteLine($"{movie}, {director}, {year}");
}
Console.WriteLine();
}
static void Main(string[] args)
{
WriteRandomNames();
}
}
Note that the second parameter of the Next(Int32, Int32) method is the exclusive upper bound. Therefore I added 1.
output:
HATRHKYAHQTGS, NCPQ, 1999
QVJAYOTTISN, LJTGJDMB, 2018
JEXJDICLRMZFRV, GJPZHFBHOTR, 1932
SKFINIGVYUIIVBD, DIZSKOS, 1958
LWWGSEIZT, AMDW, 1950
OAVZVQVFPPBY, SPEZZE, 2008
YLNTZZIXOCNENGYUL, URNJMK, 1962
ONIN, WUITIL, 1987
RJUXGORWDVQRILDWWKSDWF, MOEYPZQPV, 1946
YUQSSOPZTCTRM, UEPPXIVGERG, 1994
KILWEYC, QJZOTLKFMVPHUE, 1915
Wow, in the time it took me to write an answer, three or more others appeared. They all seem like pretty good answers to me, but since I went to the trouble of writing this code, here you go. :)
I focused on using the same Random in different ways, because I think that's what you were asking about.
using System;
using System.Collections.Generic;
using System.Linq;
Random rnd = new Random(1950);
GenerateRandomNames();
void GenerateRandomNames()
{
for (int j = 0; j < 100; j++)
{
// here's one way to get a random string
string name = Guid.NewGuid().ToString().Substring(0, 5);
string description = new string(GetRandomCharacters(rnd.Next(5,16)).ToArray());
string cleaner = new string(GetCleanerCharacters(rnd.Next(5, 16)).ToArray());
string preferred = new string(GetPreferredRandomCharacters(rnd.Next(5, 16)).ToArray());
int year = rnd.Next(1896, DateTime.Now.Year + 1);
Console.WriteLine($"{year}\t{preferred}");
Console.WriteLine($"{year}\t{cleaner}");
Console.WriteLine($"{year}\t{name}\t{description}");
Console.WriteLine();
}
Console.WriteLine();
}
// Not readable
IEnumerable<char> GetRandomCharacters(int length = 5)
{
for (int i = 0; i < length; i++)
{
yield return Convert.ToChar(rnd.Next(0, 255));
}
}
// gives you lots of spaces
IEnumerable<char> GetCleanerCharacters(int length = 5)
{
for (int i = 0; i < length; i++)
{
char c = Convert.ToChar(rnd.Next(0, 255));
if (char.IsLetter(c))
{
yield return c;
}
else
{
yield return ' ';
}
}
}
// Most readable (in my opinion), but still nonsense.
IEnumerable<char> GetPreferredRandomCharacters(int length = 5)
{
for (int i = 0; i < length; i++)
{
bool randomSpace = rnd.Next(0, 6) == 3;
if (i > 0 && randomSpace) // prevent it from starting with a space
{
yield return ' ';
continue;
}
var c = Convert.ToChar(rnd.Next(65, 91)); // uppercase letters
if (rnd.Next(0, 2) == 1)
{
c = char.ToLower(c);
}
yield return c;
}
}
I need to generate 10 different numbers(integers). My problem is that the first and last number has to be the same. How can I make a code for this logic?
The numbers are later used to populate a polar chart.
Random random = new Random();
int randomNumber = random.Next(5, 16);
int firstRand = 0;
firstRand = randomNumber;
if(indataInt2 == 0)
{
firstRand = randomNumber;
}
else if(indataInt2 >= 360 && firstRand != randomNumber)
{
randomNumber = firstRand;
}
Something like this should do the job
List<int> randomNumber = new List<int>();
Random random = new Random();
for (int i = 0; i < 9; i++)
{
randomNumber.Add(random.Next());
}
randomNumber.Add(randomNumber[0]);
First things first, when using the Random class you can provide a seed in
which will specify how the number is generated. Therefore I provided
a seed for you. This seed is always changing so the random number will
always be different. Remember, Random isn't Random, Random(Seed)
is Random! The list in which you are looking for is named 'Numbers'.
Hopefully this code can help you:
using System.Collections.Generic;
using System;
namespace Degubbing
{
class DebugProgram
{
static void Main(string[] args)
{
List<int> Numbers = new List<int> { };
int Seed = DateTime.Now.Millisecond;
Random Generator = new Random(Seed);
for (int i = 0; i < 10; i++)
{
int RandomNum = Generator.Next(10000000, 20000000);
string Result = RandomNum.ToString();
Result = Result.Remove(Result.Length - 1);
Result = Result + Result[0];
Console.WriteLine(Result);
}
Console.ReadKey();
}
}
}
What's a better way to create a random 16-digit string? I've used this code, can you suggest a more efficient or elegant way to do it?
static string Random16DigitString() {
var rand = new Random();
return $"{rand.Next(100000000).ToString().PadLeft(8, '0')}{rand.Next(100000000).ToString().PadLeft(8, '0')}";
}
PS: My reason for making this is to create a string of the form 0.0000000000000000 so I would use it in the following way:
var myString = "0." + Random16DigitString();
Your solution depends on string manipulation that will slow it down.
Try:
private static Random r = new Random();
static string Random16DigitString() {
var v = new char[16];
for (var j = 0; j < 16; j++) v[j] = (char)(r.NextDouble()*10 + 48);
return new string(v);
}
This will be faster since it doesn't depend on string operations like concatenation or interpolation. It just pokes random characters into a char array and then converts that array to a string. Executing your solution 100 million times takes about 47 seconds on my machine and my code takes about 27 seconds to produce the same results.
r.Next(10) + 48 would work in the above code but it's actually a little slower. r.Next(48,57) is even slower.
Your code could be simpler, also. $"{rand.Next(100000000):D8}{rand.Next(100000000):D8}" would do the same thing. It's about the same time to execute.
Here's the code I ended up using:
static readonly Random rnd = new Random();
static string Q() {
// https://stackoverflow.com/questions/767999/random-number-generator-only-generating-one-random-number/768001#768001
// It was decided to use a lock instead of [ThreadStatic] because this api object is designed to be used by many threads simultaneously.
lock (rnd) {
// Get a string representing a positive number greater than 0 and less than 1 with exactly 16 decimal places.
// Original implementation
//return $"0.{rnd.Next(100000000).ToString().PadLeft(8, '0')}{rnd.Next(100000000).ToString().PadLeft(8, '0')}";
// This works but is slow
//return rnd.NextDouble().ToString("F16");
// Found a better faster way: https://stackoverflow.com/questions/48455624/generate-random-16-digit-string/48457354#48457354
var chars = new char[18];
chars[0] = '0';
chars[1] = '.';
for (var i = 2; i < 18; i++)
chars[i] = (char)(rnd.NextDouble() * 10 + 48);
return new string(chars);
}
}
Here are the tests I used (with thanks to Jim Berg for his answer)
using System;
using System.Diagnostics;
using System.Text;
namespace NetCoreApp1 {
class Program {
static void Main(string[] args) {
var sync = new object();
var rnd = new Random();
Time("method1", () => {
var value = $"{rnd.Next(100000000).ToString().PadLeft(8, '0')}{rnd.Next(100000000).ToString().PadLeft(8, '0')}";
});
Time("method2", () => {
var value = $"{rnd.Next(100000000):D8}{rnd.Next(100000000):D8}";
});
Time("next double", () => {
var value = rnd.NextDouble().ToString("F16"); // turns out surprisingly slow, even slower than the first two
});
Time("method3", () => {
var v = new char[16];
for (var j = 0; j < 16; j++)
v[j] = (char)(rnd.NextDouble() * 10 + 48); // fastest
var value = new string(v);
});
Time("method3 with lock", () => {
lock (sync) {
var v = new char[16];
for (var j = 0; j < 16; j++)
v[j] = (char)(rnd.NextDouble() * 10 + 48); // a tiny bit slower with the lock
var value = new string(v);
}
});
Time("method4", () => {
var sb = new StringBuilder(16);
for (var j = 0; j < 16; j++)
sb.Append((char)(rnd.NextDouble() * 10 + 48)); // slower than method 3
var value = sb.ToString();
});
Console.WriteLine("Press Enter to exit.");
Console.ReadLine();
}
static void Time(string testName, Action action) {
var sw = Stopwatch.StartNew();
for (var i = 0; i < 10000000; i++)
action();
sw.Stop();
Console.WriteLine($"{testName}: {sw.ElapsedMilliseconds}ms");
}
}
}
I'm making a webshop for school and had a quick question.
I'm trying to write a code that generates a random coupon code and it actually works (did some extreme programming in Console Application), but it's simply not efficient.
static void Main(string[] args)
{
Random r = new Random();
string ALphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int size = 4;
char[] code1 = new char[size]
char[] code2 = new char[size]
char[] code3 = new char[size]
for (int i = 0; i < size; i++)
{
code1[i] = Alphabet[r.Next(Alphabet.Length)];
code2[i] = Alphabet[r.Next(Alphabet.Length)];
code3[i] = Alphabet[r.Next(Alphabet.Length)];
}
string code4 = new string(code1);
string code5 = new string(code2);
string code6 = new string(code3);
Console.WriteLine(code4 + " - " + code5 + " - " + code6);
Console.ReadLine();
}
This works.. somehow. But I would like to see it more efficient, because when I want to generate 100 coupons... this isn't really the way to do that.
I did see something on joining strings, use string.Insert to get that " - " in between and loop it multiple times, but I couldn't get a clear tutorial on how to do that with... well this kind of code.
Anyone got a efficient and (preferable) easy solution?
=======
UPDATE!
this does end up in a database eventually
You could be using a StringBuilder for this:
StringBuilder sb = new StringBuilder();
Random r = new Random();
string Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int size = 16;
for (var i = 0; i < size; i++)
{
sb.Append(Alphabet[r.Next(Alphabet.Length)]);
}
Console.WriteLine(sb.ToString());
If you want less code you can make use of a GUID and format it.
Guid.NewGuid().ToString("N").Substring(0, 16);
Update, just saw you needed some formatting between each part of the coupon, so I changed it a litle bit:
StringBuilder sb = new StringBuilder();
Random r = new Random();
string Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int pieces = 3, pieceSize = 4;
for (var i = 0; i < pieces; i++)
{
if(i != 0)
sb.Append(" - ");
for (var j = 0; j < pieceSize; j++)
{
sb.Append(Alphabet[r.Next(Alphabet.Length)]);
}
}
Console.WriteLine(sb.ToString());
Code is not quite good, but for school app will play I guess )
static string GenerateCoupon(Random r)
{
string Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int size = 4;
char[] code1 = new char[size];
char[] code2 = new char[size];
char[] code3 = new char[size];
for (int i = 0; i < size; i++)
{
code1[i] = Alphabet[r.Next(Alphabet.Length)];
code2[i] = Alphabet[r.Next(Alphabet.Length)];
code3[i] = Alphabet[r.Next(Alphabet.Length)];
}
string code4 = new string(code1);
string code5 = new string(code2);
string code6 = new string(code3);
return string.Format("{0}-{1}-{2}", code4, code5, code6);
}
static void Main(string[] args)
{
Random rnd = new Random();
for (int i = 0; i < 100;i++ )
Console.WriteLine(GenerateCoupon(rnd));
Console.ReadLine();
}
I have made this code to get from 2a3b to aabbb. This also has to apply when no numbers are given. Like aa2b => aabb.
The program is fully working but my problem is, it takes in alot of space. I think it is my split but my array will be like this if the input is 2a2b:
2
NULL
NULL
a
2
NULL
NULL
b
Does someone know what i'm doing wrong? Is it my split?
static void Main(string[] args)
{
string test = "";
int intNumber = 1;
string value = "2a2b";
string[] array = new string[20];
int count = 1;
array = Regex.Split(value, "(\\d{0,2})");
while (count < array.Length)
{
int num;
if (array[count] != "")
{
bool isNumeric = int.TryParse(array[count], out num);
if (!isNumeric)
{
test = test + string.fill(array[count], intNumber);
test = test + array[count];
Console.WriteLine(test);
intNumber = 1;
}
else
{
intNumber = num;
}
}
count++;
}
Console.WriteLine("woord:" + test);
Console.ReadLine();
How about using a simple Regex.Replace?
string input = "2a3bcccc";
string output = Regex.Replace(
input,
#"(\d+)(\w)",
m => new String(m.Groups[2].Value[0],int.Parse(m.Groups[1].Value)));
result : aabbbcccc
A simpler way to resolve your problem is to get rid of regex, the array creation would be like:
char[] array = value.ToArray();
The code, with the minor corrections due to the array and some improvements being a char array (intead of a string array):
static void Main(string[] args)
{
string test = "";
int intNumber = 1;
string value = "2a2b";
foreach (char c in value.ToArray())
{
int num;
bool isNumeric = int.TryParse(c.ToString(), out num);
if (!isNumeric)
{
test = test + new string(c, intNumber);
Console.WriteLine(test);
intNumber = 1;
}
else
{
intNumber = num;
}
}
Console.WriteLine("woord:" + test);
Console.ReadLine();
}
Quick test program works like a charm without using a regex.
const string value = "aa2b";
var result = "";
for (var i = 0; i < value.Length; i++)
{
int num;
if (Int32.TryParse(value.Substring(i, 1), out num))
{
for (var j = 0; j < num; j++)
{
result += value.Substring(i + 1, 1);
}
i++;
}
else
{
result += value.Substring(i, 1);
}
}
textBox1.AppendText("woord:" + result);
I generally try to avoid Regex, unless there is a complex pattern I need to verify.
Here is my solution to your problem:
string k = Console.ReadLine();
string t = "";
int count = 0, next;
for (int i = 0; i < k.Length; i++)
{
while (int.TryParse(k[i].ToString(), out next)) // Find the count of the next letter
{
count = count * 10 + next; // If count had a 2, and the next character is 3 (means we need to calculate 23), simply multiply the previous count by 10, and add the new digit
i++; // Move to the next character
}
t += new String(k[i], count > 0 ? count : 1); // Add the new sequence of letters to our string
count = 0; // Clear the current count
}
Console.WriteLine(t);
You can optimize the above, by using the StringBuilder class, but I think it's enough to understand the general solution first, rather than trying to find optimizations.