C# Programming Assignment - c#

The teacher wants me to create 2 files & insert random characters inside. Both files should be the same length. In one file a keyword "Hello" should be inserted randomly.
I did this for the first file:
var stringChars = new char[100];
var random = new Random();
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (int i = 0; i < stringChars.Length; i++)
{
stringChars[i] = chars[random.Next(chars.Length)];
}
I did this for the second file:
var stringChars2 = new char[100];
var random2 = new Random();
var chars2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZxxxxx";
for (int i = 0; i < stringChars2.Length; i++)
{
stringChars2[i] = chars2[random2.Next(chars2.Length)];
}
string string2 = new string(stringChars2);
string2 = string2.Replace("x", "\"Hello\"");
My problem is I don't know how to make the length of both files equal with the string replace trick. The second file will always be longer.

Here's an object oriented approach. I emphasize this approach since you have to perform similar operations multiple times (two). Thus, you shouldn't repeat yourself (google DRY prinicpal).
I won't tell you how to use these methods, you can figure that our for yourself:
public static class StringManipulation
{
public static string GetXRandomCharacters(int x)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
var random = new Random();
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (int i = 0; i < stringChars.Length; i++)
{
sb.Append(chars[random.Next(chars.Length)]);
}
return sb;
}
public static string InjectWordAtRandom(string str, string word)
{
var random = new Random();
int start = random.Next(str.Length - word.Length);
str.Remove(start, word.Length).Insert(start, word);
}
}
Hint: I have provided static methods but you don't have to do it that way. Try removing static from the method headers and creating an instance of the class to access it's properties.

Related

Mutating to a new string array

I'm doing an exercise that says I have to enter a phrase and put it in array, then I have to delete all the repeated characters and show the new phrase.
I did it like this but I don't know how to get char from string array and put it into another string array.
PS: I must only use the basics of C# and arrays :(
namespace Exercice3
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Entrez une phrase SVP!!");
string phrase = Console.ReadLine();
string[] phraseArray = new string[]{ phrase };
string[] newPhrase = new string[phrase.Length];
for (int i = 0; i <= phrase.Length - 1; i++)
{
for (int j = 1; j <= phrase.Length - 1; j++)
{
if (phraseArray[i] != phraseArray[j])
newPhrase = phraseArray[i]; //Probleme here
}
}
Console.WriteLine(newPhrase);
}
}
}
something like this would do it. You don't have to do it this way...
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var newColl = new List<char>();
foreach(char c in "aaabbbccc".ToCharArray())
{
if (!newColl.Contains(c))
newColl.Add(c);
}
Console.WriteLine(new string(newColl.ToArray()));
}
}
Output:
abc
Array-only method
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
const string orig = "aaabbbcccddd";
int origLen = orig.Length;
char[] newArr = new char[origLen]; // get max possible spots in arr
int newCount = 0;
for(int i = 0; i < origLen; i++)
{
bool yes = false;
for(int j = 0; j < newCount + 1; j++)
{
if (newArr[j] == orig[i])
{
yes = true;
break;
}
}
if (!yes)
{
newArr[newCount] = orig[i];
newCount++;
}
}
Console.WriteLine(new string(newArr));
}
}
Output:
abcd
The main problem here is that you are using arrays of strings. That is inappropriate because you are trying to iterate the characters of the string.
You need to construct your array of characters like this:
char[] phraseArray = phrase.ToCharArray();
This should allow you the ability to iterate the set of characters, check for duplicates, and form the new character array.
The reason why you're getting an IndexOutOfRangeException is because if you look at the two arrays:
string[] phraseArray = new string[]{ phrase };
And
string[] newPhrase = new string[phrase.Length];
The length of both arrays are completely different, phraseArray has a length of 1 and newPhrase will be set to the length of your phrase, so if you insert a world of more than 1 character both arrays will not match and then either:
if (phraseArray[i] != phraseArray[j])
Or
newPhrase = phraseArray[i];
Will fail, specially newPhrase = phraseArray[i];, because here you're trying to replace newPhrase an array, for a character phrase[i]. Basically your solution won't work. So what you can do is do what #Travis suggested, basically change your arrays from String[]to char[], then:
char[] phraseArray = phrase.ToCharArray();
Or Instead of using arrays you can just use another string to filter your phrase. The first string being your phrase and the second would be the string you'd add your non repeated characters to. basically this:
Console.WriteLine("Entrez une phrase SVP!!");
string phrase = Console.ReadLine();
string newPhrase = "";
// loop through each character in phrase
for (int i = 0; i < phrase.Length; i++) {
// We check if the character of phrease is within our newPhrase, if it isn't we add it, otherwise do nothing
if (newPhrase.IndexOf(phrase[i]) == -1)
newPhrase += phrase[i]; // here we add it to newPhrase
}
Console.WriteLine(newPhrase);
Don't forget to read the comments in the code.
Edit:
Based on the comments and suggestions given I implemented a similar solution:
Console.WriteLine("Entrez une phrase SVP!!");
char[] phrase = Console.ReadLine().ToCharArray();
char[] newPhrase = new char[phrase.Length];
int index = 0;
// loop through each character in phrase
for (int i = 0; i < phrase.Length; i++) {
// We check if the character of phrease is within our newPhrase, if it isn't we add it, otherwise do nothing
if (Array.IndexOf(newPhrase, phrase[i]) == -1)
newPhrase[index++] = phrase[i]; // here we add it to newPhrase
}
Console.WriteLine(newPhrase);

Can we call a method in the same class C#

I have the below scenario. I need to call a method which is implemented in the same class. But it is throwing errors. How can we rewrite this?
public class A
{
Random random = new Random(2);
string Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string randomString = GenerateString(5);
public string GenerateString(int size)
{
char[] chars = new char[size];
for (int i = 0; i < size; i++)
{
chars[i] = Alphabet[random.Next(Alphabet.Length)];
}
return new string(chars);
}
}
Will this scenario works?
You need to learn about constructors.
Specifically, in your code you need a constructor initializing randomString. Also, Alphabet is never going to change during execution, so it is a great candidate to become const.
public class A {
const string Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public A()
{
random = new Random(2);
randomString = GenerateStrig(5);
}
public string GenerateString(int size)
{
char[] chars = new char[size];
for (int i = 0; i < size; i++)
{
chars[i] = Alphabet[random.Next(Alphabet.Length)];
}
return new string(chars);
}
string randomString;
Random random;
}
Hope this helps.
You cannot access non-static method GenerateString in static context.
You can write your code just like this:
public class A
{
static Random _random = new Random(2);
const string Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string _randomString = GenerateString(5);
public static string GenerateString(int size)
{
char[] chars = new char[size];
for (int i = 0; i < size; i++)
{
chars[i] = Alphabet[random.Next(Alphabet.Length)];
}
return new string(chars);
}
}
Another possibility is to turn randomString field into read-only property:
string randomString => GenerateString(5);
all you have to do is to add > after =; further refactoring:
public class A
{
//TODO: Random(2) for debug only; Random() for real life
readonly Random random = new Random(2);
// Alphabet is a constant isn't it?
const string Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// read-only property; initial value is GenerateString(5)
//TODO: You may want to capitalize the property - RandomString
string randomString => GenerateString(5);
public string GenerateString(int size)
{
// Validation
if (size < 0)
throw new ArgumentOutOfRangeException(nameof(size), "size must be non-negative");
// Linq is often compact and readable
return string.Concat(Enumerable
.Range(0, size)
.Select(i => Alphabet[random.Next(Alphabet.Length)]));
}
}
Edit: As Progman noticed in comments property (and thus GenerateString(5)) will be executed each time when accessed, e.g.
A a = new A();
// call randomString 3 times
string test = string.Join(Environment.NewLine, Enumerable
.Range(0, 3).Select(i => a.randomString));
Console.Write(test);
will print out three different values
RE5Z3
BSG80
R10ID
Change what you have to include a default constructor that you call that from.
public class A
{
Random random;
string Alphabet;
string randomString;
public A()
{
Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
random = new Random(2);
randomString = GenerateString(5);
}
public string GenerateString(int size)
{
char[] chars = new char[size];
for (int i = 0; i < size; i++)
{
chars[i] = Alphabet[random.Next(Alphabet.Length)];
}
return new string(chars);
}
}
It's generally considered best practice to initialize all of your member variables inside the constructor rather than when you declare them, it helps with readability and maintainability.

User input to chose an amount of letter and number from an array in C#

I am trying to learn C# and I am making a password generator. I have set an array with the letters and number I want the program to use.
String alphabet[] = {"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
I am trying to write a piece of code in a for loop that will pick random letters or numbers any amount of length that the user inputs.
Example for
(y in alphabet (PwLength));
I just can't figure out how to get it to cycle through the loop choosing random letters.
You can use infinite random chars generator:
IEnumerable<char> GetRandomChars()
{
string alphabet =
"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Random random = new Random();
while (true)
yield return alphabet[random.Next(alphabet.Length)];
}
Take first N random characters and create string:
var result = new String(GetRandomChars().Take(length).ToArray());
You should use Random here. The idea is to get the password length from user and set the allowed characters and then use Random to generate the password.
public static string CreatePassword(int passwordLength)
{
const string allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789!#$?_-";
char[] chars = new char[passwordLength];
Random rd = new Random();
for (int i = 0; i < passwordLength; i++)
chars[i] = allowedChars[rd.Next(0, allowedChars.Length)];
return new string(chars);
}
String password = "";
for(int i = 0; i < USERINPUTLENGTH; i++)
{
//Get Random Char
String randomChar = alphabet[Random.next(alphabet.length)];
password += randomChar;
}
You don't need to loop over the alphabet, but loop once for each character you want in the generated password.
string GeneratePassword(int pwLength)
{
string alphabet = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var builder = new StringBuilder();
var random = new Random();
for(var i = 0; i < pwLength; i += 1) {
builder.Append(alphabet[random.Next(alphabet.Length)]);
}
return builder.ToString();
}

DateTime.Now.Ticks is too slow

I am making a password generator which can generate a password.
var listOfCharacters = "abcdefghijklmnopqrstuvwxyz" //the chars which are using
chars = listOfCharacters.ToCharArray();
string password = string.Empty;
for (int i = 0; i < length; i++)
{
int x = random.Next(0, chars.Length); //with random he is picking a random char from my list from position 0 - 26 (a - z)
password += chars.GetValue(x); // putting x (the char which is picked) in the new generated password
}
if (length < password.Length) password = password.Substring(0, length); // if the password contains the correct length he will be returns
return password;
My random:
random = new Random((int)DateTime.Now.Ticks);
I am looking for a faster way to generate a password than using Ticks, because its not fast enough for me. I am looking for a simple code which i can easy put in my above code. I am just a beginner in C#. So that i still can use int x = random.Next(0, chars.Length); but instead of Random.next a faster one.
EDIT:
When i want two generate two passwords in a short time .Ticks is to slow
My test code:
[TestMethod]
public void PasswordGeneratorShouldRenderUniqueNextPassword()
{
// Create an instance, and generate two passwords
var generator = new PasswordGenerator();
var firstPassword = generator.Generate(8); //8 is the length of the password
var secondPassword = generator.Generate(8);
// Verify that both passwords are unique
Assert.AreNotEqual(firstPassword, secondPassword);
}
You could use the hashcode of a Guid as seed value for your Random instance. It should be random enough for your case.
random = new Random(Guid.NewGuid().GetHashCode());
Either create the Random instance once at startup or use the RNGCryptoServiceProvider.
// Create the random instance only once.
private static Random _Random = new Random();
static void Main(string[] args)
{
var listOfCharacters = "abcdefghijklmnopqrstuvwxyz".ToList();
var result = new StringBuilder();
for (int i = 0; i < 20; i++)
{
// Consider creating the provider only once!
var provider = new RNGCryptoServiceProvider();
// The same is true for the byte array.
var bytes = new byte[4];
provider.GetBytes(bytes);
var number = BitConverter.ToInt32(bytes, 0);
var index = Math.Abs(number % listOfCharacters.Count);
result.Append(listOfCharacters[index]);
}
Console.WriteLine(result.ToString());
Console.ReadKey();
}
Bias testing
static void Main(string[] args)
{
var listOfCharacters = "abcdefghijklmnopqrstuvwxyz".ToList();
var occurences = new Dictionary<char, int>();
foreach (var character in listOfCharacters)
{
occurences.Add(character, 0);
}
var provider = new RNGCryptoServiceProvider();
var bytes = new byte[4];
for (int i = 0; i < 1000000; i++)
{
provider.GetBytes(bytes);
var number = BitConverter.ToInt32(bytes, 0);
var index = Math.Abs(number % listOfCharacters.Count);
occurences[listOfCharacters[index]]++;
}
var orderedOccurences = occurences.OrderBy(kvp => kvp.Value);
var minKvp = orderedOccurences.First();
var maxKvp = orderedOccurences.Last();
Console.WriteLine("Min occurence: " + minKvp.Key + " Times: " + minKvp.Value);
Console.WriteLine("Max occurence: " + maxKvp.Key + " Times: " + maxKvp.Value);
Console.WriteLine("Difference: " + (maxKvp.Value - minKvp.Value));
Console.ReadKey();
}
The result is that between the highest occurrence and the lowest is a value somewhere between 700 - 800 which means the bias is somewhere at 0.08% and the two characters with the maximum difference always differs. So i really can't see any bias.
The following program generates ~500 passwords / millisecond on my computer:
class Program
{
static void Main(string[] args)
{
var g = new Generator();
IEnumerable<string> passwords = new List<string>();
var startTime = DateTime.Now;
passwords = g.GetPassword().ToList();
}
}
class Generator
{
Random r = new Random(Guid.NewGuid().GetHashCode());
string randomCharsList;
const int length = 8;
const int randomLength = 8000;
const string listOfCharacters = "abcdefghijklmnopqrstuvwxyz";
public Generator()
{
CreateRandom();
}
private void CreateRandom()
{
var randomChars = new StringBuilder();
string password = string.Empty;
for (int i = 0; i < randomLength + length; i++)
{
var random = new Random(i * Guid.NewGuid().ToByteArray().First());
int x = random.Next(0, listOfCharacters.Length);
randomChars.Append(listOfCharacters[x]);
}
randomCharsList = randomChars.ToString();
}
public IEnumerable<string> GetPassword()
{
int pos;
var startTime = DateTime.Now;
while ((DateTime.Now - startTime).Milliseconds < 1)
{
pos = r.Next(randomLength);
yield return randomCharsList.Substring(pos, length);
}
}
}
Just wanted to add a note here about the thread safety issue in generating random numbers (such as a high volume webserver where we ran into this issue).
Essentially, Random class is NOT thread safe and if collision occurs, it will return 0 (not what i expected) which needless to say can really wreak havoc in your logic :) So if using in a multi-threaded environment then make sure to protect access to any shared Random objects.
See section on the 'The System.Random class and thread safety' at https://msdn.microsoft.com/en-us/library/system.random(v=vs.110).aspx for more details.
Hope this helps someone.

Why is my loop returning the same value from a method that I am calling? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Random number generator only generating one random number
My code below is doing this and I don't know why:
IF my toEmailAddresses array contains 2 e-mail addresses, uniqueID[0] and uniqueID[1] will return the same value generated from the Util.CreateRandomPassword(16) method call.
If I step through the code, then both uniqueID[0] and uniqueID[1] will contain different values like it should. But if I run the code as usual, for some reason, the same value gets assigned to my uniqueID array: uniqueID[0] and uniqueID[1] will contain the same value.
I even put in the string tempRandomPassword = null and then assign that to the value returned from the CreateRandomPassword method, but that does not work either.
What am I doing wrong?
//toEmailAddresses.Count array will have two e-mail addresses in it.
string[] uniqueID = new string[2];
for (int i = 0; i < toEmailAddresses.Count(); i++)
{
string tempRandomPassword = null;
tempRandomPassword = Util.CreateRandomPassword(16);
uniqueID[i] = tempRandomPassword;
}
public static string CreateRandomPassword(int passwordLength)
{
//http://madskristensen.net/post/Generate-random-password-in-C.aspx
string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";
char[] chars = new char[passwordLength];
Random rd = new Random();
for (int i = 0; i < passwordLength; i++)
{
chars[i] = allowedChars[rd.Next(0, allowedChars.Length)];
}
return new string(chars);
}
You're creating a new instance of Random with the default seed on every invocation. If the seed is the same it will produce the same sequence of numbers. Store the instance and use that for all invocations.
Your creating a new Random object each time, and since it uses time as a default seed, your getting the same seed, and thus the same numbers.
Make it a field of the class and only create it once.
This is why it worked when you stepped through it by the way. The extra time allowed the seed to change and return different results.
It is because your method uses
Random rd = new Random();
This local instance of Random will auto-initialize using the clock but when two instances are created too close together (in time) they will use the same seed and produce the same random sequence.
As long as you're not calling this from multiple threads you can use a static field as a simple fix:
private static Random _rd = new Random();
public static string CreateRandomPassword(int passwordLength)
{
string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";
char[] chars = new char[passwordLength];
// Random rd = new Random();
...
}
Use thread sleep in the loop
private void button3_Click(object sender, EventArgs e)
{
string[] uniqueID = new string[2];
string[] toEmailAddresses = new string[2];
toEmailAddresses[0] = "a#1.com";
toEmailAddresses[1] = "b#1.com";
for (int i = 0; i < toEmailAddresses.Count(); i++)
{
uniqueID[i] = CreateRandomPassword(16);
System.Threading.Thread.Sleep(10);
}
for (int i = 0; i < uniqueID.Count(); i++)
MessageBox.Show(i.ToString() + " : " + uniqueID[i]);
}

Categories