ArgumentsOutOfRangeExeption in a list<T> - c#

Im getting this exeption thrown when the method is invoked. the list contains exactly 52 objects(number of cards).
Any suggestions what may cause it? maybe the Add and RemoveAt Methods? Or maybe the Random?
The compiler also tell the the problem is in deck.Add(temp[j]); line.
public void Shuffle()
{
List<Card> temp = new List<Card>();
Random rand = new Random();
for (int i = 0; i < 52; i++)
{
for (int j = rand.Next(i, 52); j < 52; j++)
{
temp.Add(deck[j]);
deck.RemoveAt(j);
deck.Add(temp[j]);
}
}
}

Ok, let's imagine we are on the first run through the loops. First iteration of both the outer and inner loop. i is 0, and Rand(i, 52) produces 13.
So we have:
i - 0
j - 13
temp - empty list
deck - assume this is a list with 52 elements
Now let's run the three lines of code inside the loop:
temp.Add(deck[j]);
Get the 13th item of deck and add it to temp. Ok, done. temp now has 1 item.
deck.RemoveAt(j);
Remove the 13th item in deck. Ok, fine.
deck.Add(temp[j]);
Get the 13th item in temp and add it to, wait, what?1? temp only has 1 item! Exception! Exception!.
There isn't a need for the temp list in the first place. There is a very good shuffling algorithm that involves going through the original list of items once (not N times). And you just need one temp variable to hold a value while you swap it with another. Like this:
public void Shuffle()
{
Card temp;
Random rand = new Random();
for (int i = deck.Length; i >= 1; i--)
{
int j = rand.Next(0, i + 1);
temp = deck[i];
deck[i] = deck[j];
deck[j] = temp;
}
}
Done.

If you want to shuffle list of items then you can use the following method:
public static void Shuffle<T>(IList<T> arr, Random rnd)
{
for (var i = 0; i < arr.Count; i++)
{
var j = rnd.Next(i, arr.Count);
var tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
This method will help you shuffle your deck without ArgumentsOutOfRangeExeption

temp[j] does not neccessarily exist. You will need to initialize temp so it has at least j+1 entries or you need to change the line of temp[j] to something more fitting.

When you call rand.Next(i, 52), the result could be 52, which would be out of range for your deck and temporary deck.
Also, you need to initialize your temp list, as #nvoigt points out. List has a constructor that takes an integer for the initial size. You could pass in 52. See: http://msdn.microsoft.com/en-us/library/dw8e0z9z(v=vs.110).aspx.
You could have also easily debugged this yourself by looking at the value of j in your debugger.

Related

Filling a list with arrays, all arrays in the list are the same (in recursive function)

I expected the following code to fill the "outputList"-list with some arrays of random integers.
Turns out it doesn't. Every array in the "outputList"-list had the same numbers when I outputted the list on the console.
Any Ideas why this list is filled with the same arrays?
The random values are just to show that the output is always the same. I know there are some better ways to fill a list with random values.
Code:
List<int[]> outputList = new();
private static void Main()
{
Program program = new();
program.StartTest(); //start non-static StartTest()-method
}
private void StartTest()
{
int[] inputArray = new int[3]; //create array {0, 0, 0}
Test(inputArray, 10); //call Test()-method, repeat 10 times
for(int i = 0; i < outputList.Count; i++) //finally print the "outputList"
{
string outputStr = string.Join(" ", outputList[i]);
Console.WriteLine(outputStr);
}
Console.ReadLine();
}
private void Test(int[] array, int n)
{
outputList.Add(array); //add the array to the outputList
//fill array with random integers
Random rand = new();
for(int i = 0; i < array.Length; i++)
array[i] = rand.Next(0, 1000);
//call function again, if n > 0
n--;
if (n > 0)
Test(array, n);
}
Expected output
23 432 437
43
645 902
342 548 132
... (random values)
Actual output
252 612 761
252 612 761
252 612 761
... (always the same values)
I'm new here at stackoverflow, so please forgive any noobish mistakes I might have done.
EDIT
I need the values from the array for the next iteration
The problem is that you are passing a reference to the same array in every iteration of the Test method. When you modify the array inside the method, the changes are being reflected in all references to the same array.
You should create a new array for each iteration instead. Also it is inefficiently to fill a random index in each iteration because you can set values in some indexes many times and other indexes will never been set.
private void Test(int arraySize, int iterationsCount)
{
var arr = new int[arraySize];
outputList.Add(arr);
Random rand = new();
for(int i = 0; i < arraySize; i++)
arr[i] = rand.Next(0, 1000);
n--;
if (n > 0)
Test(arraySize, iterationsCount);
}
A theory moment. Collection of reference types does not store the
objects of these types. It stores only references to these objects.
That's why it is possible that 10 values of the list contain the same
reference - the address of the only array created. And accessing any
index of the list will be an access to the same object by the same
reference.
There are several issues with your code.
The biggest one - you are modifying and adding the same instance of the array (which is a reference type) the list. One of approaches is to pass the length of array into Test method and new it up there:
void StartTest()
{
Test(3 , 10); //call Test()-method, repeat 10 times
// ...
}
void Test(int arrLength, int iterations)
{
var array = new int[arrLength];
outputList.Add(array); //add the array to the outputList
//...
//call function again, if iterations > 0
iterations--;
if (iterations > 0)
Test(arrLength, iterations);
}
Read more:
C# Concepts: Value vs Reference Types
All About C# Value Types & Reference Types
The following code:
for(int i = 0; i < array.Length; i++)
array[rand.Next(0, array.Length)] = rand.Next(0, 1000);
does not fully correspond to the desired task to generate "array of random integers". It will fill some random indexes of the array, not necessarily all of them, which "works" when the same array is used but can result in to much of zeroes when arrays are newly created for each iteration. Better to change it to:
for(int i = 0; i < array.Length; i++)
array[i] = rand.Next(0, 1000);
P.S.
Also I would switch from recursive approach for Test to simple iterative one.

Storing numbers between two numbers in an array

as you can read from the title I'm trying to store all the numbers between two numbers in an array.
For example store the numbers between 21 and 43 (22,23,24,25,26,27,28,29...) in an array.
This is the code, I don't know why but it prints only the higher number minus one.
class Program
{
static void Main(string[] args)
{
int higher = 43;
int lower = 21;
int[] numbers = new int[22]; //the numbers between 21 and 43 are 22
for (int i = lower; i < higher;i++)
{
for (int a = 0; a < 22; a++)
{
numbers[a] = i;
}
}
for (int c = 0; c < 22; c++)
{
Console.WriteLine(numbers[c]);
}
Console.ReadLine();
}
}
This is the code, I don't know why but it prints only the higher number minus one.
This question will attract answers giving you a half dozen solutions you can cut and paste to do your assignment.
I note you did not ask a question in your question -- next time, please format your question in the form of a question. The right question to ask here is how do I learn how to spot mistakes in code I've written? because that is the vital skill you lack. Answers that give you the code will not answer that question.
I already gave you a link to a recent answer where I explain that in detail, so study that.
In particular, in your case you have to read the program you wrote as though you had not written it. As though you were coming fresh to the program that someone else wrote and trying to figure out what it does.
The first thing I would do is look at the inner loop and say to myself "what does this do, in words?"
for (int a = 0; a < 22; a++)
{
numbers[a] = i;
}
That is "put the value i in every slot of the array. Now look at the outer loop:
for (int i = lower; i < higher;i++)
{
put the value i in every slot of the array
}
Now the technique to use here is to logically "unroll" the loop. A loop just does something multiple times so write that out. It starts with lower, it goes to higher-1, so that loop does this:
put the value lower in every slot of the array
put the value lower+1 in every slot of the array
…
put the value higher-1 in every slot of the array
What does the third loop do?
print every item in the array
And now you know why it prints the highest number minus one multiple times. Because that's what the program does. We just reasoned it out.
Incidentally the answers posted so far are correct, but some are not the best.
You have a technique that you understand for "do something to every member of an array, and that is:
loop an indexer from 0 to the array size minus one
do something to the array slot at the indexer
But the solutions the other answers are proposing are the opposite:
loop an indexer from the lower to the higher value
compute an index
do something to the array slot at that index
It's important to understand that both are correct, but my feeling is that for the beginner you should stick with the pattern you know. How would we
loop an indexer from 0 to the array size minus one
do something to the array slot at the indexer
for your problem? Let's start with giving you a much better technique for looping the indexer:
for (int i = 0; i < numbers.Length; ++i)
That's a better technique because when you change the size of the array, you don't have to change the loop! And also you are guaranteed that every slot in the array is covered. Design your loops so that they are robust to changes and have good invariants.
Now you have to work out what the right loop body is:
{
int number = i + lower;
numbers[i] = number;
}
Now you know that your loop invariant is "when the loop is done, the array is full of consecutive numbers starting at lower".
For everytime you loop through i, you put that number in every slot of the array. The inner loop is what is causing your issue. A better solution would be:
int higher = 43;
int lower = 21;
int[] numbers = new int[21];
int index = 0;
for (int i = lower + 1; i < higher; i++) // if you want to store everything
// between 21 and 43, you need to
// start with 22, thus lower + 1
{
numbers[index] = i;
index++;
}
for (int c = 0; c < 21; c++)
{
Console.WriteLine(numbers[c]);
}
Console.ReadLine();
Replace a with a direct translation of i
for (int i = lower; i < higher;i++)
{
numbers[i-lower] = i;
}
Use below
int higher = 43;
int lower = 21;
int[] numbers = new int[22]; //the numbers between 21 and 43 are 22
for (int i = lower+1; i < higher; i++)
{
numbers[i-lower] = i;
}
for (int c = 1; c < 21; c++)
{
Console.WriteLine(numbers[c]);
}
Console.ReadLine();
I think higher & lower are variables so following will give you output
for any higher and lower numbers
class Program
{
static void Main(string[] args)
{
int higher = 43;
int lower = 21;
int numDiff = higher - lower - 1;
int[] numbers = new int[numDiff]; //the numbers between 21 and 43 are 22
for(int i = 0; i<numbers.Length; i++)
{
numbers[i] = numDiff + i + 1;
}
for(int b = 0; b<numbers.Length; b++)
{
Console.WriteLine(numbers[b]);
}
Console.ReadLine();
}
}

C#: How should I go about shuffling contents of an array?

I have an array of integers called cards[52]. Each element contains an integer that represents a card (cards[0] = 5 would represent the 6 of clubs for example).
This is how I shuffled the array. It works, but I am getting repeats.
private void shuffleCards()
{
for (int i = 0; i < cards.Length; i++)
{
int randIndex = r.Next(0, 52);
int origCard = cards[i];
cards[i] = cards[randIndex];
cards[randIndex] = origCard;
}
}
r is the Random variable I initialized in the beginning of the program.
When testing the program, I noticed I would get the same card 2 or 3 times. Obviously I cannot get repeats, they all must be different. I can't see in any way how this method gives me repeats.
How can I shuffle this array without any repeats? Thanks.
EDIT
Okay, turns out the shuffle function wasn't the problem. It is the deal() function that is causing the problem.
private void deal()
{
for (int i = 0; i < 26; i++)
{
userCards[i] = cards[i];
setUserValue(); //ignore this
}
for (int i = 26; i < 52; i++)
{
opponentCards[i - 26] = cards[i];
setOpponentValue(); //ignore this
}
}
I know for sure it isn't the shuffle function. I printed the results of all the cards to a text file and saw no iterations. However, when the cards are dealt to the user and the opponent, that's when all the iterations occur. Any advice?
There is very simple algorithm known as Fisher Yates shuffling algorithm which does the shuffling in O(n) time and O(1) space complexity.
Use a random function that generates a random index from the given set and replace the random element generated with the last index. Decrement last index and continue like this for the rest of elements.
Let the array of size n be : arr[n]
void randomize ( int arr[], int n )
{
// Use a different seed value so that we don't get same
// result each time we run this program
srand ( time(NULL) );
// Start from the last element and swap one by one. We don't
// need to run for the first element that's why i > 0
for (int i = n-1; i > 0; i--)
{
// Pick a random index from 0 to i
int j = rand() % (i+1);
// Swap arr[i] with the element at random index
swap(&arr[i], &arr[j]);
}
}
Source : Algorithm

C# WinForm Enum ToString

// in general i take random colors from an Enum and insert that into a new array.
when i ask by BoxMessage inside the loop For each Array[i] i get random colors as expected.
If i comment (\) the message box and ask for Array[1-5] outside the loop, i get the same color for all 5 message box.
I believe it related to the fact that my message box inside the loop successfully convert the Enum into a string, when i tried to convert the whole array in the loop ( array[i].ToString(); ) it didn't quite work.
please advise....
public void GetArray()
{
array = new EnumColor[5];
for (int i = 0; i < 5; i++)
{
rnd = new Random();
int rndnum = rnd.Next(0, 4);
array[i] = (EnumColor)rndnum;
MessageBox.Show(array[i].ToString());
}
MessageBox.Show(array[0].ToString());
MessageBox.Show(array[1].ToString());
MessageBox.Show(array[2].ToString());
MessageBox.Show(array[3].ToString());
MessageBox.Show(array[4].ToString());
}
for (int i = 0; i < 5; i++)
{
rnd = new Random();
int rndnum = rnd.Next(0, 4);
array[i] = (EnumColor)rndnum;
MessageBox.Show(array[i].ToString());
}
You're overwriting elements in the array, don't do this.
Retrieve elements into a temporary local variable instead (and use .Length instead of a hardcoded length)
The bug itself is caused by Random being incorrectly seeded, it's being regerated on every iteration.
Random rnd = new Random();
for (int i = 0; i < array.Length; i++)
{
int rndnum = rnd.Next(0, 4);
EnumColor selected = (EnumColor)array[i];
MessageBox.Show( selected .ToString() );
}
You are getting the same color because you are declaring random instance each time in your loop, just move the declaration outside:
rnd = new Random();
for (int i = 0; i < 5; i++)
{ ... }
If you like to learn more about why Random class works that way you can take a look at this answer.
The problem is indeed the Random being re-created for every loop. But here's the full explanation.
When you create a Random, it uses the Environment.TickCount as seed value. (milliseconds since system startup). So if your loop is fast enough, this will always be the same value, so the rnd.Next function will always return the same value.
So now for the tricky part.. why did it work with the messagebox inside the loop? By showing the message, the loop became slower by waiting for you clicking the ok button. Therefore the next loop, the seed was indeed changed. That's why you got another value.

Sort two dimensional string array by id using insertion sort - C#

I'm new here and sorry If my question is stupid, but I really need you help.
I need to sort that two dimensional string array by id (the first column):
string [,] a = new string [,]
{
{"2","Pena","pena"},
{"1","Kon","kon"},
{"5","Sopol","sopol"},
{"4","Pastet","pastet"},
{"7","Kuche","kuche"}
};
The problem is that I'm sorting only the number and I want after them to sort the words. That's what I did so far
static void Main(string[] args)
{
string [,] a = new string [,]
{
{"2","Pena","pena"},
{"1","Kon","kon"},
{"5","Sopol","sopol"},
{"4","Pastet","pastet"},
{"7","Kuche","kuche"}
};
int b = a.GetLength(0);
Console.WriteLine(b);
Console.WriteLine(a[0,0]);
Console.WriteLine(a[0,1]);
Console.WriteLine(a[1,0]);
InsertionSort(a, b);
Console.WriteLine();
Console.Write("Sorted Array: ");
printArray(a);
Console.WriteLine();
Console.Write("Press any key to close");
Console.ReadKey();
}
public static void InsertionSort(string[,] iNumbers, int iArraySize)
{
int i, j, index;
for (i = 1; i < iArraySize; i++)
{
for (int k = 0; k < iNumbers.GetLength(1); k++)
{
index = Convert.ToInt32(iNumbers[i, 0]);
j = i;
while ((j > 0) && (Convert.ToInt32(iNumbers[j - 1, 0]) > index))
{
iNumbers[j, k] = iNumbers[j - 1, k];
j = j - 1;
}
iNumbers[j, 0] = Convert.ToString(index);
}
}
}
static void printArray(string[,] iNumbers)
{
for (int i = 0; i < iNumbers.GetLength(0); i++)
{
for (int k = 0; k < iNumbers.GetLength(1); k++)
{
Console.Write(iNumbers[i, k] + " ");
}
}
Console.WriteLine();
}
Unfortunatelly as output I get
1 Pena pena 2 Kon kon 4 Sopol sopol 5 Pastet pastet 7 Kuche kuche
I would be really grateful if you could help me.
Based on the nature of the example and the question, I am guessing that this is a homework assignment and so must be implemented in a fashion that is a) not far from your current example, and b) actually demonstrates an insertion sort.
With that in mind, the following is a corrected version of your example that works:
public static void InsertionSort(string[,] iNumbers, int iArraySize)
{
int i, j, index;
for (i = 1; i < iArraySize; i++)
{
index = Convert.ToInt32(iNumbers[i, 0]);
j = i;
while ((j > 0) && (Convert.ToInt32(iNumbers[j - 1, 0]) > index))
{
for (int k = 0; k < iNumbers.GetLength(1); k++)
{
string temp = iNumbers[j, k];
iNumbers[j, k] = iNumbers[j - 1, k];
iNumbers[j - 1, k] = temp;
}
j = j - 1;
}
}
}
I made two key changes to your original code:
I rearranged the k and j loops so that the k loop is the inner-most loop, rather than the j loop. Your j loop is the one performing the actual sort, while the k loop is what should be actually moving a row for an insertion operation.
In your original example, you had this reversed, with the result that by the time you went to sort anything except the index element of a row, everything looked sorted to the code (because it's only comparing the index element) and so nothing else got moved.
With the above example, the insertion point is determined first, and then the k loop is used simply to do the actual insertion.
I added logic to actually swap the elements. In your original code, there wasn't really a swap there. You had hard-coded the second part of a swap, simply copying the index element to the target, so the swap did work for the index element. But it wouldn't have achieved the swap for any other element; instead, you'd just have overwritten data.
With the above, a proper, traditional swap is used: one of the values to be swapped is copied to a temp local variable, the other value to be swapped is copied to the location of the first value, and then finally the saved value is copied to the location of the second.
The above should be good enough to get you back on track with your assignment. However, I will mention that you can get rid of the k loop altogether if your teacher will allow you to implement this using jagged arrays (i.e. a single-dimensional array containing several other single-dimensional arrays), or by using a second "index array" (i.e. where you swap the indexes relative to the original array, but leave the original array untouched).

Categories

Resources