Adding specific numbers from one sequence to another - c#

I feel like this task should not be done this way...
My sequenceY length is not equal to number of steam numbers because you can't assign int[] length with int that have 0 as a starting value.
Therefore my sequenceY have a lot of 0 inside and I can't print the whole sequence. I even tried adding this after for loop:
sequenceY = new int[steamnumbercounter];
But it didn't work ... Why ?
My other question is how do programmers deal with sequences that have unknown length?
I managed to print only steam numbers but the task says print sequenceY not only part of it.
// 4. sequenceX[20] is made of random numbers from 1 to 30 ,
// sequenceY is made of steam numbers from sequenceX. Print sequneceY.
int[] nizx = new int[20];
int[] nizy = new int[20];
int n = 0;
int steamnumbercounter = 0;
Random rnd = new Random();
for (int i = 0; i < nizx.Length; i++)
{
nizx[i] = rnd.Next(1, 30);
if (nizx[i]%2==0)
{
nizy[n] = nizx[i];
n++;
steamnumbercounter++;
}
Console.Write("{0} , ", nizx[i]);
}
for (int i = 0; i < steamnumbercounter; i++)
{
Console.WriteLine("{0} , ",nizy[i]);
}

Partial code review along with an answer.
But it didn't work ... Why ?
That code didn't work because you're reassigning sequenceY to a completely new value.
My other question is how do programmers deal with sequences that have unknown length?
So, with that known we can do a few things here: create an array and use Array.Resize, use a List<T>, fill the initial array then swap it for one of the right size which is filled.
I'm going to assume a "steam" number is an even one.
Your naming is not good: nizx and nizy don't convey the meaning or line up with the problem.
I'm going to demonstrate the last option (since you stated that you don't know how to use many of the moderately complex parts of .NET in this class yet, which is fine): fill the initial array and swap it for a new one. This will run in O(n^2) time (sorta).
So, let's start with our source array.
int[] sequenceX = new int[20];
Next we'll define our destination array to be the same size as our source array. (This is the maximum number of values that could be stored in it, we'll shrink it later.)
int[] sequenceY = new int[sequenceX.Length];
Then we need a variable to hold how many numbers we found that meet our criteria:
int steamNumbers = 0;
And lastly, our Random.
Random random = new Random();
Then, we look through all our sequenceX as you did, but we'll update the logic a bit.
for (int i = 0; i < sequenceX.Length; i++)
{
sequenceX[i] = random.Next(1, 30);
if (sequenceX[i] % 2 == 0)
{
sequenceY[steamNumbers] = sequenceX[i];
steamNumbers++;
}
}
So our code looks almost the same as yours, but we have one more thing to do: since you only want sequenceY to contain steamNumbers we have to shrink it or something.
int[] tempSequenceY = sequenceY;
sequenceY = new int[steamNumbers];
for (int i = 0; i < steamNumbers; i++)
{
sequenceY[i] = tempSequenceY[i];
}
Now sequenceY only has your steam numbers in it.
Final code:
int[] sequenceX = new int[20];
int[] sequenceY = new int[sequenceX.Length];
int steamNumbers = 0;
Random random = new Random();
for (int i = 0; i < sequenceX.Length; i++)
{
sequenceX[i] = random.Next(1, 30);
if (sequenceX[i] % 2 == 0)
{
sequenceY[steamNumbers] = sequenceX[i];
steamNumbers++;
}
}
int[] tempSequenceY = sequenceY;
sequenceY = new int[steamNumbers];
for (int i = 0; i < steamNumbers; i++)
{
sequenceY[i] = tempSequenceY[i];
}
// Print your `sequenceY` here.
You could extract this to a method pretty easily as well:
public int[] GetSteamNumbers(int sequenceCount, int randomMinimum, int randomMaximum)
{
int[] sequenceX = new int[sequenceCount];
int[] sequenceY = new int[sequenceX.Length];
int steamNumbers = 0;
Random random = new Random();
for (int i = 0; i < sequenceX.Length; i++)
{
sequenceX[i] = random.Next(randomMinimum, randomMaximum);
if (sequenceX[i] % 2 == 0)
{
sequenceY[steamNumbers] = sequenceX[i];
steamNumbers++;
}
}
int[] tempSequenceY = sequenceY;
sequenceY = new int[steamNumbers];
for (int i = 0; i < steamNumbers; i++)
{
sequenceY[i] = tempSequenceY[i];
}
return sequenceY;
}
And then call it with:
int[] steamNumbers = GetSteamNumbers(20, 1, 30);
Of course, for the more advanced users (this doesn't help you, but it may help others) we can do something as follows using LINQ:
var random = new Random();
var sequenceY = Enumerable.Range(1, 20)
.Select(x => random.Next(1, 30))
.Where(x => x % 2 == 0)
.ToArray();
Which should have the same effect. (Just demonstrating that there are still things in C# to look forward to in the future.)
Disclaimer: I wrote this entire answer outside of the IDE and without actually compiling it, I make no guarantees to the accuracy of the code but the procedure itself should be fairly straight forward.

The thing with arrays in C# is that they are of fixed size.
You'll have to iterate through and re-create it or use a IEnumerable that has dynamic sizes, such as Lists.
Solution here would be to use a List that contains your integers and then you would use nizx.Add(rnd.Next(1, 30));

Elaborating on my comment above: You can create a 'fake' list by concatenating the values you need in a string, separated by commas. The string.Split(',') will give you the resulting array that you need.
Given a string of form "a,b,c,d" string.Split(',') will create the array ["a","b,"c","d"]. The code:
{
int[] nizx = new int[20];
string numberString = string.Empty;
int n = 0;
Random rnd = new Random();
for (int i = 0; i < nizx.Length; i++)
{
nizx[i] = rnd.Next(1, 30);
if (nizx[i] % 2 == 0)
{
numberString += nizx[i] + ",";
n++;
}
}
var numberArray = numberString.Split(',');
for (int i = 0; i < n; i++)
{
Console.WriteLine("{0} , ", numberArray[i]);
}
}

Related

Copy odd numbers from array into another array

Im new to programming and struggling with this task:
In array X [20] random numbers from 1 to 30 are entered, in array Y enter only odd numbers from array X.
Print down Y.
int[] x = new int[20];
Random rnd = new Random();
int counter = 0;
int[] y;
for (int i = 0; i < x.Length; i++)
{
x[i] = rnd.Next(1, 30);
if (x[i] % 2 !=0 )
{
y = new int[counter];
counter++;
y[counter] = x[i];
}
}
foreach (int number in y)
{
Console.WriteLine(number);
}
Im having problems to fill Y array with odd numbers without defining length of Y, I tried with adding counter but getting some errors all the time,
If someone can help me with some suggestions that would be helpful, thank you!
This looks like homework, so I guess using a more appropriate collection such as a List<int> is out of the question, just as using Linq.
At y = new int[counter]; you're reinitializing the array. This happens each iteration, so your final array only holds the latest added value, and all values before that will be set to their default: 0.
You could've seen this by debugging your code by setting breakpoints, stepping through the code and inspecting your variables. You could then also have provided a more proper problem description than "getting some errors".
If you know the input is never larger than 20, you can initialize the output array to the same size and keep a counter of how many values you copied (the latter of which you already do).
Then when printing, only print the elements up till that count with a for loop instead of foreach.
So something like this:
int[] x = new int[20];
int[] y = new int[x.Length];
Random rnd = new Random();
int counter = 0;
for (int i = 0; i < x.Length; i++)
{
x[i] = rnd.Next(1, 30);
if (x[i] % 2 != 0)
{
y[counter] = x[i];
counter++;
}
}
for (int i = 0; i < counter; i++)
{
Console.WriteLine(y[i]);
}
Your problem is that you create a new y array for each odd number you find. You need to create the array only once and then fill it.
Since you don't know how many odd numbers there will be, I suggest to use a List<int> instead:
int[] x = new int[20];
Random rnd = new Random();
List<int> y = new List<int>(); // create the list before the loop
for (int i = 0; i < x.Length; i++)
{
x[i] = rnd.Next(1, 30);
if (x[i] % 2 !=0 )
y.Add(x[i]); // add odd number to list
}
foreach (int number in y)
{
Console.WriteLine(number);
}
See, In your case you are not aware about the number of odd numbers in that random array. so Array will not be a right choice here if you are following the current implementation. If you want the output as array, then Why not a simple LINQ with Where like this example:
First you collect all random numbers to your array as you are doing currently:
int[] randomIntegers = new int[20];
Random rnd = new Random();
for (int i = 0; i < randomIntegers.Length; i++)
{
randomIntegers[i] = rnd.Next(1, 30);
}
Now you have the all random numbers in x now perform the following operation:
int[] oddValues = randomIntegers.Where(a=> a % 2 !=0).ToArray();

c# Read 'n' amount of random lines from txt file

I am attempting to read (n) amount of random lines from a text file with about 200 entries (lines) and populate a listbox called "recSongs". I have provided some simple code which retrieves one random line from the text file, but I want retrieve n amount.
Here is my code.
var lines = File.ReadAllLines(#"file.txt");
var r = new Random();
var randomLineNumber = r.Next(0, lines.Length - 1);
var line = lines[randomLineNumber];
recSongs.Items.Add(line);
How about:
var lines = File.ReadAllLines("file.txt").OrderBy(x => Guid.NewGuid()).Take(n);
n will be the input , i.e no of lines you need
List <string> text = File.ReadLines("file.txt").Take(n).ToList();
Edit
If you need random lines, you could do,
string[] lines = File.ReadAllLines(#"C:\YourFile.txt");
List<string> source = new List<string>();
int n = 10;
for (int i = 0; i < n; i++)
{
source.Add(lines[new Random().Next(lines.Length)]);
}
var lines = File.ReadAllLines(#"file.txt");
var r = new Random();
var randomized = lines.OrderBy(item => r.Next()); //randomize the list
recSongs.Items.AddRange(randomized.Take(N).ToArray()); //Add N amount to listbox
This solution also avoids duplicate randoms
Probably the easiest way, though not the most memory-efficient, is to slurp the file into an in-memory collection of its lines, then Shuffle() the lines and take however many you want:
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> input)
{
var buffer = input.ToArray();
//Math.Random is OK for "everyday" randomness;
//use RNGCryptoServiceProvider if you need
//cryptographically-strong randomness
var rand = new Random();
//As the loop proceeds, the element to output will be randomly chosen
//from the elements at index i or above, which will then be swapped
//with i to get it out of the way; the yield return gives us each
//shuffled value as it is chosen, and allows the shuffling to be lazy.
for (int i = 0; i < buffer.Length; i++)
{
int j = rand.Next(i, buffer.Length);
yield return buffer[j];
//if we cared about the elements in the buffer this would be a swap,
//but we don't, so...
buffer[j] = buffer[i];
}
}
...
string[] fileLines = GetLinesFromFile(fileName); //a StreamReader makes this pretty easy
var randomLines = fileLines.Shuffle().Take(n);
Some notes:
This should work fairly well for a text file of about 200 lines; beyond a couple hundred thousand lines, you'll start having memory problems. A more scalable solution would be to shuffle an array of line numbers, then use those to seek for and read the specific lines you want, discarding all the others.
This solution produces the random lines in random order. If you want to preserve the order of the lines from the file, do the line-number variant, sorting the line numbers you select, then just keep the lines in that order after reading them out of the file.
Try this
var lines = File.ReadAllLines(#"file.txt");
var r = new Random();
int noLines = 10;// n lines
for (int i = 0; i < noLines; i++)
{
var randomLineNumber = r.Next(0, lines.Length - 1);
var line = lines[randomLineNumber];
recSongs.Items.Add(line);
}
You could do something like:
HashSet<int> linesHash = new HashSet<int>();
var lines = file.ReadLines();
for (int i = 0; i < numLinesToGet; i++)
{
int line=0;
do
{
line = rand.Next(0, lines.Length);
}while(linesHash.Contains(line));
linesHash.Add(line);
linesAdded.Add(lines[line]);
}
Note that if the amount of lines to get is greater than the actually number of lines my code would never end, so some checks must be done prior to execute the for loop.
This will add numLines random lines to your collection. Note that there is a chance that there will be duplicates.
var lines = File.ReadAllLines(#"file.txt");
var r = new Random();
int numLines = 5;
for (int i = 0; i < numLines; i++)
{
recSongs.Items.Add(lines[r.Next(0, lines.Length - 1)]);
}
To enforce unique items, you could do something like this:
for (int i = 0; i < numLines; i++)
{
var randomItem = string.Empty;
do
{
randomItem = lines[r.Next(0, lines.Length - 1)];
} while (recSongs.Contains(randomItem));
recSongs.Items.Add(randomItem);
}
But now note that it is possible that it will never exit. The joys of Random!
var lines = File.ReadAllLines(#"file.txt");
var random = new Random();
var lines = Enumerable.Repeat( -1, n ) // -1 is a filler and is discarded by the select.
.Select( _ => random.Next(0, lines.Length - 1 ) )
.Select( index => lines[index] );
foreach( var line in lines )
{
recSongs.Items.Add(line);
}

How can I make random numbers that never repeat in array?

listBox1.Items.Clear();
int[] sayısal = new int[6];
Random rastgele = new Random();
for (int i = 0; i < 6; i++)
{
do
{
sayısal = rastgele.Next(1, 50);
}
while (listBox1.Items.IndexOf(sayısal) != -1);
listBox1.Items.Add(sayısal);
}
When I did like this, I take an error that calls
"Cannot implicitly convert type 'int' to 'int[]' "
in line "sayısal = rastgele.Next(1, 50);". What can I do for it?
You can generate sequence 1..50 and shuffle it (i.e. sort by random value):
Random rastgele = new Random();
int[] sayısal = Enumerable.Range(1, 50) // generate sequence
.OrderBy(i => rastgele.Next()) // shuffle
.Take(6) // if you need only 6 numbers
.ToArray(); // convert to array
Your code is not working, because you are trying to assign generated item to array variable.
sayısal = rastgele.Next(1, 50);
It should be instead:
do {
sayısal[i] = rastgele.Next(1, 50);
} while(listBox1.Items.IndexOf(sayısal[i]) != -1);
As I already pointed in comments, it's better to separate UI logic and array generation. I.e.
// generate array (optionally move to separate method)
int itemsCount = 6;
int[] items = new int[itemsCount]; // consider to use List<int>
Random random = new Random();
int item;
for(int i = 0; i < itemsCount; i++)
{
do {
item = random.Next(1, 50);
} while(Array.IndexOf(items, item) >= 0);
items[i] = item;
}
// display generated items
listBox1.Items.Clear();
for(int i = 0; i < items.Length; i++) // or use foreach
listBox1.Items.Add(items[i]);
Because Random.Next method returns an int, not int[]. And there is no implicit conersation from int[] to int.
Return Value
Type: System.Int32
A 32-bit signed integer greater than or equal to minValue and less than maxValue; that is, the range of return values includes minValue but not maxValue. If minValue equals maxValue, minValue is returned.
If you want to fill your array, you can use Enumerable.Range like lazyberezovsky mentioned.
This method takes an integer array and randomly sorts them.
So fill an array with a loop then use this to randomly sort the array.
You should credit one of the others as they were first to post with valid answers. I just thought another way to do this would be good.
amount is the amount of times you want the array to randomize. The higher the number the higher the chance of numbers being random.
private Random random = new Random();
private int[] randomizeArray(int[] i, int amount)
{
int L = i.Length - 1;
int c = 0;
int r = random.Next(amount);
int prev = 0;
int current = 0;
int temp;
while (c < r)
{
current = random.Next(0, L);
if (current != prev)
{
temp = i[prev];
i[prev] = i[current];
i[current] = temp;
c++;
}
}
return i;
}
Be careful in your choice of data structures and algorithms, pick the wrong one and you'll wind up with O(n^2). A reasonable solution IMHO is a typed hash table (i.e. dictionary) which will give you O(n):
Random rnd = new Random();
var numbers = Enumerable
.Range(1, 1000000)
.Aggregate(new Dictionary<int, int>(), (a, b) => {
int val;
do {val = rnd.Next();} while (a.ContainsKey(val));
a.Add(val, val);
return a;
})
.Values
.ToArray();
Still not ideal though as performance depends on the array size being significantly smaller than the set of available numbers and there's no way to detect when this condition isn't met (or worse yet when it's greater, in which case the algorithm will go into an infinite loop).

Randomizing a list of chars in a string, C#

I've been playing around / researching ways to randomize the order of chars in a string. I frankly just don't understand how to do it. I've searched through the C# documentation and a handful of websites. I found one particular way of randomizing the order of chars in a string but I don't understand how it works. I've also read that the Random class isn't truly random, which would explain why the results are so similar.
How exactly does the current method I'm using function (especially the OrderBy() method).
Is there a better way to do this?
Current code
string baseList = "abcdefghijklmnopqrstuvwxyz";
Random random = new Random();
string[] randLists = new string[baseList.Length];
for (int i = 0; i < baseList.Length; i++)
{
randLists[i] = new string(baseList.ToCharArray().OrderBy(s => (random.Next(2) % 2) == 0).ToArray());
Console.WriteLine(randLists[i]);
}
Console.Read();
This is my attempt at randomizing but it doesn't function at all:
*string bL = "abcdefghijklmnopqrstuvwxyz";
string[] rL = new string[bL.Length];
Random randomizer = new Random();
for (int i = 0; i < bL.Length; i++)
{
rL = new string(bL.ToCharArray().OrderBy(c => (randomizer.Next(0, 25)).ToString()));
}*
Thanks in advance for any assistance. I'll continue researching in the meantime.
Although the code that you found is short, it does not make a nicely distributed shuffle of the original string: the randomizer is likely to give you the same numbers in the process of generating a shuffle, increasing a probability that the corresponding characters would remain in the same order relative to each other as in your original string.
One solution to this problem is using Fisher–Yates shuffle. It is easy to implement (you need to stay away from common implementation errors, though).
Since string is immutable, you would need to shuffle an array of characters, and then make a string from it.
To add to the suggestion of the Fisher-Yates shuffle, here's a code sample, just ignore the test assertion, just trying to debug and make sure it's random enough.
[TestMethod]
public void RandomizeText()
{
string baseList = "abcdefghijklmnopqrstuvwxyz";
char[] result = baseList.ToCharArray();
Shuffle<char>(result);
var final = string.Join("", result);
final.Should().NotMatch(baseList);
}
public void Shuffle<T>(T[] array)
{
var random = new Random();
for (int x = 0; x < 100; x++)
{
for (int i = array.Length; i > 1; i--)
{
// Pick random element to swap.
int j = random.Next(i); // 0 <= j <= i-1
// Swap.
T tmp = array[j];
array[j] = array[i - 1];
array[i - 1] = tmp;
}
}
}
Another example...
static void Main(string[] args)
{
string baseList = "abcdefghijklmnopqrstuvwxyz";
Console.WriteLine(baseList);
string shuffled = Shuffle(baseList);
Console.WriteLine(shuffled);
Console.ReadLine();
}
static Random R = new Random();
static string Shuffle(string list)
{
int index;
List<char> chars = new List<char>(list);
StringBuilder sb = new StringBuilder();
while (chars.Count > 0)
{
index = R.Next(chars.Count);
sb.Append(chars[index]);
chars.RemoveAt(index);
}
return sb.ToString();
}

Avoiding random duplicates

System.Random generator = new Random(DateTime.Now.Millisecond);
int[] lotteryNumber = new int[7];
Console.WriteLine("Your lottery numbers: ");
for (int i = 0; i<7; i++)
{
lotteryNumber[i] = generator.Next(1, 37);
Console.Write("{0} ",lotteryNumber[i]);
}
Console.ReadLine();
I need to make a program that prints 7 lottery numbers, but without duplicates. The code above prints 7 random numbers in the range of (1-37), but duplicates appaer. I need a way to prevent duplicate numbers from appearing.
The simplest approach IMO would be to generate a sequence of all the possible numbers (i.e. 1-37), shuffle the collection, then take the first seven results.
Searching on Stack Overflow for "Fisher-Yates shuffle C#" will find lots of examples.
In fact, you could modify the Fisher-Yates shuffle to yield results as you took them, so you could write a method such as:
var numbers = Enumerable.Range(1, 37).Shuffle().Take(7).ToList();
You could take a dictionary but make sure that you prevent duplicate key insertion. Keys of dictionary would serve as the unique numbers you need
You could toss them into a HashSet<int>. If you Add and it returns false, generate a new number.
If you're trying to pick numbers from a range without repetitions, you need to create an array of all the possible numbers and then "shuffle" a random selection out:
int[] allPossibleNumbers = Enumerable.Range(1, 37).ToArray();
int[] lotteryNumber = new int[7];
for (int i = 0; i < 7; i++)
{
int index = r.Next(i, 37);
lotteryNumber[i] = allPossibleNumbers[index];
allPossibleNumbers[index] = allPossibleNumbers[i];
// This step not necessary, but allows you to reuse allPossibleNumbers
// rather than generating a fresh one every time.
// allPossibleNumbers[i] = lotteryNumber[i];
}
Generate a list with your 37 items.
Then in your for, select one and delete the selected
Maybe this could help, if you get the existing number just try to find new one that isn't in the array:
static void Main(string[] args)
{
System.Random generator = new Random(DateTime.Now.Millisecond); int[] lotteryNumber = new int[7];
Console.WriteLine("Your lottery numbers: ");
for (int i = 0; i < 7; i++)
{
int lNumber = 0;
do
{
lNumber = generator.Next(1, 37);
}
while (lotteryNumber.Contains(lNumber));
lotteryNumber[i] = lNumber;
Console.Write("{0} ", lotteryNumber[i]);
}
Console.ReadLine();
}
HashSet<int> set = new HashSet<int>();
System.Random generator = new Random(DateTime.Now.Millisecond);
while(set.Count < 7){
set.Add(generator.Next(1,37);
}
That should work, since a HashSet will automatically ignore duplicates. Just loop until the set reaches the number of units you need. Only potential problem is it has the POTENTIAL (unlikely) to loop for a long time, but it should eventually respond.
so I took your original code...found some logic errors and added the fix you were looking for to prevent random number duplicates.
Enjoy!
System.Random generator = new Random(DateTime.Now.Millisecond);
int[] lotteryNumber = new int[7];
int lowerBounds = 1;
int upperBounds = 8;
int maxNumberLotteryValues = 7;
if ( ( upperBounds - lowerBounds ) < (maxNumberLotteryValues))
{
Console.Write("Warning: Adjust your upper and lower bounds...there are not enough values to create a unique set of Lottery numbers! ");
}
else
{
Console.WriteLine("Your lottery numbers: ");
for (int i = 0; i < maxNumberLotteryValues; i++)
{
int nextNumber = generator.Next(lowerBounds, upperBounds);
int count = lowerBounds; //Prevent infinite loop
while ((lotteryNumber.Contains(nextNumber))
&& (count <= upperBounds))
{
nextNumber = generator.Next(lowerBounds, upperBounds);
count++; //Prevent infinite loop
}
lotteryNumber[i] = nextNumber;
Console.Write("{0} ", lotteryNumber[i]);
}
}
Console.ReadLine();
const int nBalls = 37;
const int nPicks = 6;
int[] balls = new int[nPicks];
Random rnd = new Random(DateTime.Now.Millisecond);
int remainingBalls=nBalls;
int remainingPicks=nPicks;
for (int i = 1; i <= nBalls; i++)
{
if (rnd.Next(1, remainingBalls+1) <= remainingPicks)
balls[--remainingPicks]=i;
remainingBalls--;
}
Console.WriteLine(string.Join(",",balls));
Will outperform Shuffle and HashSet methods as nPicks/nBalls gets larger.

Categories

Resources