I'm new to programming and I have decided to give myself a challenge by creating a random word generator based on user input.
I'm trying to put the user's words inside of an array and then display a random word from the the array. When I run the program I am able to enter up to four words and then I receive an error: "Array index is out of range."
Is there a limit to how many times I can resize an array?
using System;
namespace RandomWordGenerator
{
class MainClass
{
public static void Main (string[] args)
{
Random r = new Random ();
string[] words = new string[1];
Console.WriteLine ("Enter words for the random word generator. ");
int a = 0;
while(!(Console.ReadLine().Equals("END"))){
words[a] = Console.ReadLine();
a++;
Array.Resize(ref words, a);
}
Console.WriteLine ();
Console.WriteLine (words[r.Next (a)]);
}
}
}
Arrays in c# are immutable, which is to say they cannot be changed after creating them.
What you want is a List<string>, which can be resized at will.
class MainClass
{
public static void Main (string[] args)
{
Random r = new Random ();
List<string> words = new List<string>();
Console.WriteLine ("Enter words for the random word generator. ");
int a = 0;
while(!(Console.ReadLine().Equals("END"))){
words.Add(Console.ReadLine());
}
Console.WriteLine ();
Console.WriteLine (words[r.Next(words.Count)]);
}
}
Array.Resize is actually not named very well, since it does something different than actual resizing. From the MSDN documents:
This method allocates a new array with the specified size, copies elements from the old array to the new one, and then replaces the old array with the new one.
The List<> class is designed for a dynamically sized collection, and in many cases is a better choice than a raw array.
The reason you're seeing an IndexOutOfRangeException is because you're trying to access an array with an index outside of its current range:
int a = 0;
while(!(Console.ReadLine().Equals("END")))
{
words[a] = Console.ReadLine();
a++;
Array.Resize(ref words, a);
}
After the first iteration, you're trying to access words[a] where a = 1, but the array index is zero based, hence you're trying to access words[1] where the array only has 1 element located at the words[0] index, because you allocated a new array with Array.Resize, passing a (1) as its size. That is why you're seeing the exception.
A problem to your solution is as #rossipedia stated. Simply use a List<T>.
The suggestions about using List are all good and valid, but direct answer to your specific question is following -
Array.Resize(ref words, a);
should be changed to -
Array.Resize(ref words, a + 1);
Reason - You start with a=0;, set words[0] to value read, set a=1, and then ask runtime to resize your array from size 1 to 1.. rest follows.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am new to programming. C# is my first programming language.
I have an assignment where I have to create and test out a bubble sort algorithm and a selection sort algorithm using arrays. I think I understand those now.
The next part of the assignment I am having some trouble on.
I have to write a program that will ask the user for a number (n) and create 1000 arrays of n size.
So if the user enters 5 for the number, my program has to create and sort 1000 arrays that are of length 5.
I have to use the bubble sort and the selection sort methods I created.
After I do that, I have to initiate a variable called running_time to 0. I have to create a for loop that iterates 1000 times and in the body of the loop i have to create an array of n random integers.
Then I have to get the time and set this to the start time. My professor said to notice that the sort is started after each array is built, so I should time the sort process only.
Then I have to get the time and set it to end time. I have to subtract the start time from end time and add the result to the total time.
Once the program has run, note
1. the number of items sorted
2. the average running time for each array (total time/1000)
Then I have to repeat the process using 500, 2500, and 5000 as the size of the array.
This is my code for creating one array with n number of spaces and filled with random integers.
//Asks the user for number
Console.WriteLine("Enter a number: ");
n = Convert.ToInt32(Console.ReadLine());
//Creates an array of the length of the user entered number
int[] randArray = new int[n];
//Brings in the random class so we can use it.
Random r = new Random();
Console.WriteLine("This is the array: ");
//For loop that will put in a random number for each spot in the array.
for (int i = 0; i < randArray.Length; i++) {
randArray[i] = r.Next(n);
Console.Write(randArray[i] + " ");
}
Console.WriteLine();
THIS IS MY CODE FOR THE BUBBLE SORT ALGORITHM:
//Now performing bubble sort algorithm:
for (int j = 0; j <= randArray.Length - 2; j++) {
for (int x = 0; x <= randArray.Length - 2; x++) {
if (randArray[x] > randArray[x + 1]) {
temp = randArray[x + 1];
randArray[x + 1] = randArray[x];
randArray[x] = temp;
}
}
}
//For each loop that will print out the sorted array
foreach (int array in randArray) {
Console.Write(array + " ");
}
Console.WriteLine();
THIS IS MY CODE FOR THE SELECTION SORT ALGORITHM:
//Now performing selection sort algorithm
for (int a = 0; a < randArray1.Length - 1; a++) {
minkey = a;
for (int b = a + 1; b < randArray1.Length; b++) {
if (randArray1[b] < randArray1[minkey]) {
minkey = b;
}
}
tempSS = randArray1[minkey];
randArray1[minkey] = randArray1[a];
randArray1[a] = tempSS;
}
//For loop that will print the array after it is sorted.
Console.WriteLine("This is the array after the selection sort algorithm.");
for (int c = 0; c < randArray1.Length; c++) {
Console.Write(randArray1[c] + " ");
}
Console.WriteLine();
This is very overwhelming as I am new to this and I am still learning this language.
Can someone guide me on the beginning on how to create 1000 different arrays filled with random numbers and then the rest. I would appreciate it greatly. Thank you.
So you have a several questions that has overwhelmed you.
Let's look at each one
Take user input
Console.WriteLine("Enter a length");
while (!int.TryParse(Console.ReadLine(), out var length))
Console.WriteLine("omg! you had one job");
Calling a method with an out argument
Starting with C# 7.0, you can declare the out variable in the argument
list of the method call, rather than in a separate variable
declaration. This produces more compact, readable code, and also
prevents you from inadvertently assigning a value to the variable
before the method call. The following example is like the previous
example, except that it defines the number variable in the call to the
Int32.TryParse method.
Fill Array
private static Random _rand = new Random();
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
...
public static string RandomString(int length)
{
var result = Enumerable.Range(0, length)
.Select(s => chars[_rand.Next(length)])
.ToArray();
return new string(result);
}
Create array of random chars
var arr = Enumerable.Range(0, size)
.Select(i => RandomString(length)).ToArray();
How to time something
var sw = Stopwatch.StartNew();
// something to time
var milliseconds = sw.ElapsedMilliseconds
Now map it all together, I'll leave these details up to you
Additional Resources
Enumerable.Range(Int32, Int32) Method
Generates a sequence of integral numbers within a specified range.
Enumerable.Select Method
Projects each element of a sequence into a new form.
Stopwatch Class
Provides a set of methods and properties that you can use to
accurately measure elapsed time.
Random Class
Represents a pseudo-random number generator, which is a device that
produces a sequence of numbers that meet certain statistical
requirements for randomness.
I've a line in the bottom part of the main screen of the game, that every time the scene is loaded, it shows a different tip (how to play, how to change music...).
The question is that I'm using Random.Range for that but, honestly, I'll prefer a way where all tips are showed, one by one in a random way, but without repeating any of them.
My code is as follows:
int randNum;
void Start () {
randNum = Random.Range(0,5);
}
void Update () {
switch (randNum)
{
case 0:
// blah, blah, blah...
case 1...
How can I achieve what I want?
Thans for yout timeeee :)
You can remove the switch statement and store each message in a list.
var tips = new List<string>();
tips.Add("The clouds are white");
...
Then you can randomize the elements in the list (more on that here) and show tips one by one. All you need is to keep track of the index. Example:
// This needs to be a field.
int index = 0;
void ShowTip()
{
// TODO: make sure index is not equal or greater than tips.Count
tip = tips[index];
index++;
// Display the tip
}
What you can do is to shuffle your list of tip. The Fisher-Yates shuffle is one of the most common.
static Random _random = new Random();
static void Shuffle<T>(T[] array)
{
int n = array.Length;
for (int i = 0; i < n; i++)
{
// Use Next on random instance with an argument.
// ... The argument is an exclusive bound.
// So we will not go past the end of the array.
int r = i + _random.Next(n - i);
T t = array[r];
array[r] = array[i];
array[i] = t;
}
}
public static void Main()
{
string[] array = { "tip 1", "tip 2", "tip 3" };
Shuffle(array);
foreach (string value in array)
{
Console.WriteLine(value);
}
}
output
net
dot
perls
source
Suppose your messages are stored in a list of string declared at the global level together with your random class and with an additional List of strings initially empty
List<string> needToDisplayMessages = new List<string>();
List<string> base_messages = new List<string>{"message1","message2","message3","message4","message5"};
Random rnd = new Random();
In your update method check if the list of messages to be displayed is empty and if yes copy the messages from the list with the predefined message. Now use the random instance to choose the index of the message to display and get it from the dynamic list. Finally remove the message from the list of message still to be displayed.
void Update () {
// We refill the list if it is empty
if(needToDisplayMessages.Count == 0)
needToDisplayMessages.AddRange(base_messages);
// Choose a random number topped by the count of messages still to be displayed
int index = rnd.Next(0, needToDisplayMessages.Count);
string message = needToDisplayMessages[index];
..... display the message someway .....
// Remove the message from the list
needToDisplayMessages.RemoveAt(index);
}
Of course, if you want to display the messages in sequential order there is no need of this but (as already explained) just an index. But if you want to randomly choose the message until you have shown all of them and then restart the cycle, perhaps this approach is not too much complex.
using System;
namespace reverse
{
class Program
{
static void Main(string[] args)
{
int[] a = new int [10];
for (int i= 0; i<a.Length; i++)
{
a[i] = int.Parse(Console.ReadLine());
}
}
}
}
here I can get values from a user by pressing enter key after each time i give the value but I want to give value as a whole with comma. Thanks!
I would suggest to gradually step towards functional programming.
Why?
Weel, with words from Eric Lippert from "Functional programming for beginners"
I will talk about the “why” a little bit, but basically it boils down to
a great many bugs are caused by bad mutations.
By taking a page
from functional style and designing programs so that variables and
data structures change as little as possible, we can eliminate a
large source of bugs.
Structuring programs into small functions
whose outputs each depend solely on inputs
makes for programs that
are easy to unit test.
the ability to pass functions as data
allows us to create new and interesting control flows and patterns,
like LINQ.
Rewriting your code
Use Linq in a single and simple line:
int [] res =
Console.ReadLine () // read the input
.Split (',') // transform it into an array
.Take (10) // consider only the first 10 strings
.Select (int.Parse) // transform them into int
.ToArray (); // and finally get an array
You can add a check after the Split and before Take:
.Where (d => {int t; return int.TryParse (d, out t);}).Take
Try this one and read comments to get more info :
static void Main()
{
string input = Console.ReadLine(); // grab user input in one whole line
string[] splitted = input.Split(','); // split user input by comma sign ( , )
int[] a = new int[splitted.Length]; // create a new array that matches user input values length
for(int i = 0; i < splitted.Length; i++) // iterate through all user input values
{
int temp = -1; // create temporary field to hold result
int.TryParse(splitted[i], out temp); // check if user inpu value can be parsed into int
a[i] = temp; // assign parsed int value
}
}
This method will ensure that program will execute even if user wont input numerics. For example if user input will be :
1 , 2,3,45,8,9898
The output will be :
{ 1, 2, 3, 45, 8, 9898 }
But if the input will be :
1,adsadsa,13,4,6,dsd
The output will be :
{ 1, 0, 13, 4, 6, 0 }
I'm working on a football league fixture project on C# Console Application.
I'm trying to choose random teams from the array which contains the teams which plays at their home and away.
When I'm trying to generate 9 random numbers, only 8 numbers are generated and 0 are not, so the code can't break the for loop.
I suppose that the problem is that the if statement does not allow to generate the same number and int array's elements' default value is 0.
Here is the code and the output:
C# Code Output
int randomHome; //Random number genetator for choosing a random iteration value from home array which containss the teams which plays at their home
int randomAway; //Random number genetator for choosing a random iteration value from awayarray which containss the teams which plays at away
Random randomNum = new Random();
int[] randomHomeNumArray = new int[home.Length]; //array will hold the randomHome values and home array is the array which is holding the team's iteration values which plays at their home
int[] randomAwayNumArray = new int[away.Length]; //array will hold the randomAway values and away array is the array which is holding the team's iteration values which plays at away
for (int homeArrayCounter = 0; homeArrayCounter < randomHomeNumArray.Length; homeArrayCounter++)
{
randomHome = randomNum.Next(home.Length)
if (!randomHomeNumArray.Contains(randomHome) )
{
randomHomeNumArray[homeArrayCounter] = randomHome; //It will hold the randomHome values
Console.WriteLine(homeArrayCounter + ". iterasyon in Home " + randomHomeNumArray[homeArrayCounter]);
}
else
{
homeArrayCounter--;
}
}
Console.WriteLine("\n\n");
for (int awayArrayCounter = 0; awayArrayCounter < randomAwayNumArray.Length; awayArrayCounter++)
{
randomAway = randomNum.Next(randomAwayNumArray.Length);
if (!randomAwayNumArray.Contains(randomAway))
{
randomAwayNumArray[awayArrayCounter] = randomAway; //It holds the random valures from away array which contains the teams which plays at away
Console.WriteLine(awayArrayCounter + ". iterasyon in Away " + randomAwayNumArray[awayArrayCounter]);
}
else
{
awayArrayCounter--;
}
}
When you initalize an array, it has the value 0 by default for each index. When you are using the random number, it always skips 0 because it already exists.
You can try like this:-
for(int i= 0; i<randomHomeNumArray.Length; i++){
randomHomeNumArray[i] = -1;
}
for (int homeArrayCounter = 0; homeArrayCounter < randomHomeNumArray.Length; homeArrayCounter++)
{
do{
randomHome = randomNum.Next(home.Length);
} while(!randomHomeNumArray.Contains(randomHome));
randomHomeNumArray[homeArrayCounter] = randomHome; //It will hold the randomHome values
Console.WriteLine(homeArrayCounter + ". iterasyon in Home " + randomHomeNumArray[homeArrayCounter]);
}
It appears you're trying to just randomize arrays.
Try this instead:
Random randomNum = new Random();
int[] randomHomeNumArray = Enumerable.Range(0, home.Length).OrderBy(_ => randomNum.Next()).ToArray();
int[] randomAwayNumArray = Enumerable.Range(0, away.Length).OrderBy(_ => randomNum.Next()).ToArray();
That's it. Done.
Your problem is the default initialization of your arrays:
int[] randomHomeNumArray = new int[home.Length];
This creates an array filled with 0s, because 0 is the default value for int.
So your if condition
if (!randomHomeNumArray.Contains(randomHome))
is always false for 0 because 0 is already contained in the array.
You may initialize your arrays instead like this:
int[] randomHomeNumArray = Enumerable.Repeat(-1, home.Length).ToArray();
So you fill it with -1 instead of 0 and your if condition works.
Because int is not a null-able data type, by default, an int[] gets initialized with zeroes. So even if you think it's an empty array, it's actually an array with all elements set to zero.
To rectify the problem, you can consider using an int?[] (null-able int array) instead. Or, you can initialize the array with either a negative integer or some integer greater than the maximum inclusive upper bound. Better yet, to achieve what you want, in a better way, use the solution provided by #Enigmativity, and mark his answer accepted, if it helped.
This question already has answers here:
Dynamic array in C#
(9 answers)
Closed 7 years ago.
static void Main(string[] args)
{
int numberOfTheWords = 1;
string[] words = new string[numberOfTheWords];
Console.WriteLine("You can exit from program by writing EXIT ");
Console.WriteLine("Enter the word: ");
for(int i = 0; i < numberOfTheWords; i++)
{
words[i] = Console.ReadLine();
if (words[i] == "EXIT")
break;
else
numberOfTheWords++;
}
}
Guys I am trying to expand the lengt of the array but "numberOfTheWords" variable is in the "for loop' scope" so it does not effect the global "numberOfTheWord" variable and i cannot expand the array length. What I am trying to achieve is to make dynamic array. I do not want to declare the length of the array. When the user input a word, the length of the array will be increased automatically. Can you help me about how to do this?
This can be easily done with a List.
Example:
List<string> words = new List<string>();
...
words.Add(Console.ReadLine());
Lists are dynamically expanding and you don't have to manage the size of the list on your own. The .NET Framework does that for you. You can also insert an item anywhere in the middle or delete one from any index.
You just need to use List:
var words = new List<string>();
An array does not dynamically resize. A List does. With it, we do not need to manage the size on our own. This type is ideal for linear collections not accessed by keys.