Array to new string - c#

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();
}

Related

I'm generating a list of 100 random "names", now I need to follow it up with 100 more names and 100 random numbers. C#

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;
}
}

Random number in Do While Loop

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?

How to decompress RLE in C#?

So basically I want to input something such as "05A03R02B" and for the program to return "AAAAARRRBB".
I'm relatively new to coding and it's a task I've been set so I have really no idea how to do it and haven't known what to try.
This snipped does your job:
private byte blockLength = 3;
private byte numLength = 2;
private void StringWorker(string input, out string output)
{
var len = input.Length;
if(len%blockLength!=0)
{
throw new ArgumentException("len has to be a multiple of blockLength");
}
var keys = new char[len/blockLength];
var values = new byte[len/blockLength];
var buffer = input.SubString(0,blockLength); //fill 1st block
//parse string into keys and values
for (var i = blockLength+1; i < s.Length; i++)
{
int index = i/blockLength;
//check for new block
if((i-1)%blockLength==0)
{
//assign values
values[index] = Int32.Parse(buffer.SubString(i-blockLength-1,numLength);
keys[index] = buffer[i-1];
//clear buffer
buffer="";
}
//add new char to buffer
buffer+=input[i];
}
//compose new string from keys and values
var sb = enw StringBuilder();
for(var i = 0; i < keys.Length; i++)
{
var value = values[i];
var key = keys[i];
for(var j = 0; j < value; j++)
{
sb.Append(key);
}
}
output = sb.ToString();
}

How to generate password on the following standard

I want to generate a password on the following standard.
One capital letter
10 Small letters
four numbers at the end
Code I have
//Gnerating a random password
string allowedChars = "";
allowedChars = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,";
allowedChars += "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,";
allowedChars += "1,2,3,4,5,6,7,8,9,0,!,#,#,$,%,&,?";
char[] sep = { ',' };
string[] arr = allowedChars.Split(sep);
string passwordString = "";
string tempString = "";
int PasswordLength = 16;
Random rand = new Random();
for (int i = 0; i < Convert.ToInt32(PasswordLength); i++)
{
tempString = arr[rand.Next(0, arr.Length)];
passwordString += tempString;
}
There is no need to create both an upper and a lower value set. We have code for changing case. You could also extract the actual picking to a separate method, that would make it easier to test.
Here is my attempt:
void Main()
{
char[] lowerCase = new char[] {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
char[] numbers = new char[] {'0','1','2','3','4','5','6','7','8','9'};
// Create the Random outside the method to avoid reseeding
Random random = new Random();
// Pick one char and make it uppercase
string password = PickRandomValueFromValueSet(1, lowerCase, random).ToUpper();
// Pick 10 lowercase chars
password+= PickRandomValueFromValueSet(10, lowerCase, random);
// Pick 4 digits
password+= PickRandomValueFromValueSet(4, numbers, random);
Console.Out.WriteLine.(password);
}
string PickRandomValueFromValueSet(int number, char[] valueSet, Random random)
{
string result = "";
for (int i = 0; i < number; i++)
{
result += valueSet[random.Next(0, valueSet.Length)];
}
return result;
}
I don't see why !,#,#,$,%,& and ? were allowed as numbers in the question. I have omitted those.
You need to add different chars to your password string in this way:
string lowerChars = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,";
string[] lowerCharsArr = lowerChars.Split(sep);
string upperChars = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,";
string[] upperCharsArr = upperChars.Split(sep);
string numbers = "1,2,3,4,5,6,7,8,9,0";
string[] numbersArr = numbers.Split(sep);
string others = "!,#,#,$,%,&,?";
string[] othersArr = others.Split(sep);
string passwordString = "";
int PasswordLength = 16;
Random rand = new Random();
passwordString += upperChars[rand.Next(0, upperChars.Length)];
for (int i = 1; i < Convert.ToInt32(PasswordLength -4); i++)
{
passwordString += lowerChars[rand.Next(0, lowerChars.Length)];
}
for (int i = 0; i < 4; i++)
{
passwordString += numbersArr[rand.Next(0, numbersArr.Length)];
}
Here's one way you could do this, optionally shuffling the result with the extension method .Shuffle, but if you really want to keep the order of upper first, then lower, then 4 digit/symbols at the end just leave that out.
namespace PasswordGen
{
public class Program
{
private static Random _random = new Random();
static void Main(string[] args)
{
var nonAlphaSymbols = "1234567890!##$%&?";
var password = new[] { (char)_random.Next('A', 'Z' + 1) } // upper case character
.Concat(Enumerable.Range(0, 10).Select(a => (char)_random.Next('a', 'z' + 1)) // 10 lower case
.Concat(Enumerable.Range(0, 4).Select(a => nonAlphaSymbols[_random.Next(0, nonAlphaSymbols.Length)]))) // 4 from nonAlpha
.Shuffle(); // optional, if you want to shuffle the outcome
Console.WriteLine(new string(password.ToArray()));
}
}
public static class Extensions
{
private static Random _random = new Random();
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> input)
{
List<T> output = new List<T>(input);
for (int i = 0; i < output.Count; i++)
{
var swapTarget = _random.Next(i, output.Count - 1);
T temp = output[swapTarget];
output[swapTarget] = output[i];
output[i] = temp;
}
return output;
}
}
}
Example: https://dotnetfiddle.net/BLOEgy

Generate random 16-digit string

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");
}
}
}

Categories

Resources