This question already has answers here:
ArgumentOutOfRangeException on initialized List
(1 answer)
How to initialize a List<T> to a given size (as opposed to capacity)?
(16 answers)
Closed 4 years ago.
So I've been looking around for quite a while to try and find a solution to this.
I've been trying to make a card game and am stuck at a section in which I create a cad along with its properties. i decided to make it in the form of an array. The code looks like:
(not sure what happened with these first ones)
string[] dogs = System.IO.File.ReadAllLines(#"C:\Users\corin\Documents\C# coding\dogs.txt");
int individual = totalCards / 2;
Random r = new Random();
int Cards = totalCards / 2;
List<List<int>> playerCards = new List<List<int>>(Cards);
for (int x = 0; x < (Cards-2); x++)
{
playerCards[0].Add(Int32.Parse(dogs[x]));//Cards
playerCards[1].Add(r.Next(1, 6));//Drool
playerCards[2].Add(r.Next(1, 101));//Exercise
playerCards[3].Add(r.Next(1, 11));//Intelligence
playerCards[4].Add(r.Next(1, 11));//Friendliness
}
No errors are raised before I run the code but when I try it an Argument out of range exception occurs for the line: playerCards[0].Add(Int32.Parse(dogs[x]));
I tried removing it and the same error occured for the next line. I'm not sure what I've done wrong and have tried to find a solution for quite some time. If anyone has any tips or answers that would be great.
Thanks
try this :
string[] dogs = System.IO.File.ReadAllLines(#"C:\Users\corin\Documents\C# coding\dogs.txt");
int individual = totalCards / 2;
Random r = new Random();
int Cards = totalCards / 2;
List<List<int>> playerCards = new List<List<int>>();
//the missing piece
for (int i = 0; i < (Cards ); i++)
{
playerCards.add(new List<int>());
}
for (int x = 0; x < (Cards-2); x++)
{
playerCards[0].Add(Int32.Parse(dogs[x]));//Cards
playerCards[1].Add(r.Next(1, 6));//Drool
playerCards[2].Add(r.Next(1, 101));//Exercise
playerCards[3].Add(r.Next(1, 11));//Intelligence
playerCards[4].Add(r.Next(1, 11));//Friendliness
}
In addition to the previous answers: new List<List<int>>(Cards) doesn't do what you think it does. It sets capacity, not elementCount (or whatever it's called). When bounds are checked, elementCount is used, not capacity. capacity is useful when you have a good idea how many elements you have, to avoid reallocations and don't waste space.
So yes, before accessing by index you should add elements into the list manually.
Related
This question already has answers here:
Why the other list also changes if I have changed the data of one list? [duplicate]
(2 answers)
What is the difference between a reference type and value type in c#?
(15 answers)
Closed 5 years ago.
Ok, So I am new to programming in general but getting a start with C#. I am still a near absolute beginner and just writing small projects to get comfortable with the language. I decided this was what I wanted to play with, SO first I created a class Deck, that holds a list of cards. This function is what I wanted to use to shuffle the cards. I do realize this is not the most efficient way but I wanted to accomplish a "Realistic" Shuffle. This is also a rough draft off the top of my head. The code works 1 time through, but Once i call deck.RemoveRange(0,52); It removes everything, from every list, Including NewDeck, FirstCut, SecondCut. (This is just a learning experiment for me and has nothing to do with "What is useful")
Edit: Apologies for the confusing code, I still vomit whatever is in my head until the computer understands. I meant to mention I knew that the issue was an issue with Refrence Types vs. Value Types, I was just under the impression that I was creating new Items when I was in fact, Not doing so. So I wondered how that applied to .RemoveRange and if that remove just an element or removed the base reference(Books and video's never explained this so I am trying to learn from this mistake).
public static List<Card> GetNewDeck(int ShuffleTimes)
{
Deck MainDeck = new Deck();
List<Card> NewDeck = MainDeck.DeckOfCards;
List<Card> ShuffledDeck = new List<Card>();
for (int i = 0; i <= ShuffleTimes; i++)
{
Random Shuffle = new Random();
var FirstCut = NewDeck;
var SecondCut = new List<Card>();
var deck = new List<Card>();
var cut = Shuffle.Next(15, 37);
for (int c = 0; c < cut; c++)
{
SecondCut.Add(FirstCut[0]);
FirstCut.RemoveAt(0);
}
while (deck.Count != 52)
{
var rif = Shuffle.Next(1, 4);
if (rif < SecondCut.Count)
{
for (int r = 0; r < rif; r++)
{
deck.Add(SecondCut[0]);
SecondCut.RemoveAt(0);
}
}
if (rif < FirstCut.Count)
{
for (int d = 0; d < rif; d++)
{
deck.Add(FirstCut[0]);
FirstCut.RemoveAt(0);
}
}
if (rif >= SecondCut.Count && SecondCut.Count != 0)
{
for (int ri = 0; ri <= SecondCut.Count; ri++)
{
deck.Add(SecondCut[0]);
SecondCut.RemoveAt(0);
}
}
if (rif >= FirstCut.Count && FirstCut.Count != 0)
{
for (int si = 0; si <= FirstCut.Count; si++)
{
deck.Add(FirstCut[0]);
FirstCut.RemoveAt(0);
}
}
if (deck.Count == 52)
{
NewDeck = deck;
}
}
deck.RemoveRange(0, 52);
ShuffledDeck = NewDeck;
}
return ShuffledDeck;
}
When you assign one list to another, you are not making a copy of it, you are literally assigning a reference to the same list over and over. So, each time you do that, they all point to the same place. Thus, clearing one clears all.
What you probably want is to make a copy of the list. For example:
NewDeck = new List<Card>(deck);
This won't make a copy of the card objects themselves, but will create a new list that references the cards, which is probably fine for your needs.
This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 6 years ago.
So I coded a quick program to test how much difference it would make (in terms of processing speed) to check a boolean inside a foreach statement compared to checking it in a conditional statement outside of the loop. To test this I made a function generate random strings and add them to a list, but the for loop that generates the strings seems to advance too quickly without generating different strings in ever repetition. To fix this I added a Thread.Sleep(15) (15 milliseconds seems to be the minimum required to generate a different string in every repetition).
My question is this: is it possible to fix this issue without a Thread.Sleep(15)? Waiting 15 milliseconds between every repetition makes it so that the program takes a way bigger amount of time to run, which makes it highly unpractical for it's purpose (if I want to get statistically relevant data I'd have to run it around 10 thousand times for each option (the "good" and the "bad" way)). Here's the for loop in question:
for (int i = 0; i < 1000; i++) {
var stringChars = new char[8];
var random = new Random();
for (int n = 0; n < stringChars.Length; n++)
{
stringChars[n] = chars[random.Next(chars.Length)];
}
var finalString = new String(stringChars);
data.Add(finalString);
Thread.Sleep(15);
}
The problem you are getting is that you are recreating the Random class each time you iterate the loop.
The reason this is a problem is because the default seed for the Random class is the current system timestamp, which on repeated iterations could well be the same value.
Creating the Random outside of the for loop will ensure that a pseduo-random sequence is generated as you would expect.
Try this:
var random = new Random();
for (int i = 0; i < 1000; i++) {
var stringChars = new char[8];
for (int n = 0; n < stringChars.Length; n++)
{
stringChars[n] = chars[random.Next(chars.Length)];
}
var finalString = new String(stringChars);
data.Add(finalString);
}
I have a little problem over here. I have a list of questions KlausimuList and i have to form another list Atsitiktinis witch would be a random length and would have random questions taken from KlausimuList. My method works, but the problem is - questions are duplicating. Could you please write me a code where they don't? I have an idea of making a seperate int array of indexes of questions i already added, and then each time check if that question already is in that list. If it does - genererate a new number, but i just don't know how to write the code for this thing :D. Thanks in advice. Code is in c#.
static void FormuotiAtsisiktini(List<Klausimas> KlausimuList, ref List<Klausimas> Atsitiktinis)
{
Random kiek = new Random();
int kiekis = kiek.Next(1, KlausimuList.Count);
for (int i = 0; i < kiekis; i++)
Atsitiktinis.Add(KlausimuList[kiek.Next(1, KlausimuList.Count)]);
}
You could use HashSet to avoid duplicates. Add method on HashSet returns false when try adding duplicate item.
static void FormuotiAtsisiktini(List<Klausimas> KlausimuList, ref List<Klausimas> Atsitiktinis)
{
Random kiek = new Random();
int kiekis = kiek.Next(1, KlausimuList.Count);
HashSet<Klausimas> hashset= new HashSet<Klausimas>();
for (int i = 0; i < kiekis;)
{
i+= hashset.Add(KlausimuList[kiek.Next(1, KlausimuList.Count)])? 1:0; // returns true when successfully added.
}
Atsitiktinis = hashset.ToList();
}
This should work. It creates a copy of the original list and removes the already taken items from it:
static List<Klausimas> FormuotiAtsisiktini(List<Klausimas> KlausimuList)
{
Random kiek = new Random();
List<Klausimas> source = new List<Klausimas>(KlausimuList);
List<Klausimas> result = new List<Klausimas>();
int kiekis = kiek.Next(1, KlausimuList.Count);
for (int i = 0; i < kiekis; i++)
{
var match = source[kiek.Next(0, source.Count - 1)];
result.Add(match);
source.Remove(match);
}
return result;
}
What you are describing is called sampling without replacement, and a solution to that is provided in this SO post. Furthermore, to ensure that you are actually adding duplicates to your collection, consider using a HashSet instead of a List.
I'm running this code, but every time, I get the error "An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred" on the first line of the for loop. Its basically code for a multiple choice quiz question, with questions & answers stored in a 2d array.
Unfortunately, I can't seem to spot the problem. It's probably a simple error, but I'm a beginner so I'm struggling to spot it.
I've read through similar questions, but I don't understand why this line is causing problems. I've got 4 elements in my list, one is removed before the loop, so there should be 3 left. I'm only looping through 3 times, so I don't understand what the problem is.
Hopefully someone will be able to help, Thanks!
Random rndq = new Random();
Random rnda = new Random();
List<int> answers = new List<int> { 1, 2, 3, 4 };
int questionchoice = rndq.Next(0, questions.GetLength(0) - 1);
int labelchoice = rnda.Next(0, answers.Count-1);
lblQuestion.Text = questions[questionchoice, 0];
var answer = (Label)Controls["lblAns" + answers[labelchoice]];
answer.Text = questions[questionchoice, 1];
answers.Remove(labelchoice);
int j = 2;
for (int i = 0; i < 3; i++)
{
var wronganswers = (Label)Controls["lblAns" + answers[i]];
wronganswers.Text = questions[questionchoice, j];
answers.RemoveAt(i);
j++;
}
Each pass through the loop you're removing an item from the list. After the first pass your list has 3 items in it [2, 3, 4]. Next pass there are two items left [2, 4]. Then you try to get the third item from the list of two and get an exception.
Either you need to leave the list alone while looping or make sure that your loop condition actually references the length of the list. Assuming that you want to actually process all 4 items I would suggest that you remove the RemoveAt call completely.
Or if you actually want to remove the items, reverse the direction of your loop:
for (int i = answers.Count - 1; i >= 0; i--)
{
// ....
answers.RemoveAt(i);
}
This will still process all of the items in the list and leave you with nothing in the list at the end.
I have a scenario where I have a list of classes, and I want to mix up the order. For example:
private List<Question> myQuestions = new List<Question>();
So, given that this is now populated with a set of data, I want to mix up the order. My first thought was to create a collection of integers numbered from 1 to myQuestions.Count, assign one at random to each question and then loop through them in order; however, I can’t seem to find a suitable collection type to use for this. An example of what I mean would be something like this:
for (int i = 0; i <= myQuestions.Count -1; i++)
tempCollection[i] = myQuestions[rnd.Next(myQuestions.Count-1)];
But I’m not sure what tempCollection should be – it just needs to be a single value that I can remove as I use it. Does anyone have any suggestions as to which type to use, or of a better way to do this?
I suggest you copy the results into a new List<Question> and then shuffle that list.
However, I would use a Fisher-Yates shuffle rather than the one you've given here. There are plenty of C# examples of that on this site.
For example, you might do:
// Don't create a new instance of Random each time. That's a detail
// for another question though.
Random rng = GetAppropriateRandomInstanceForThread();
List<Question> shuffled = new List<Question>(myQuestions);
for (int i = shuffled.Count - 1; i > 0; i--)
{
// Swap element "i" with a random earlier element it (or itself)
int swapIndex = rng.Next(i + 1);
Question tmp = shuffled[i];
shuffled[i] = shuffled[swapIndex];
shuffled[swapIndex] = tmp;
}
You could use Linq and order by a random value:
List<string> items = new List<string>();
items.Add("Foo");
items.Add("Bar");
items.Add("Baz");
foreach (string item in items.OrderBy(c => Guid.NewGuid()))
{
Console.WriteLine(item);
}
temp Collection should be same type as myQuestions.
I would also suggest a change in your code:
for (int i = 0; i <= myQuestions.Count -1; i++)
to
for (int i = 0; i < myQuestions.Count; i++)
Does the same thing, but this is how most programers do it so it will make your code simpler to read.