getting out of range exception in bool array(c#) - c#

im trying to use random number to to pull 30 strings out of a array of 58 strings and am using a bool array to check and make sure the same number is not called twice. the method and the program always crashes with a index out of range error. here is the method.
static string[] newlist(string[] s)
{
string[] newlist = {};
bool[] issearched = new bool[s.Length];
Random callorder = new Random();
for (int i = 0; i < 31; i++)
{
int number = callorder.Next(0, s.Length);
if (issearched[number] == false)
{
newlist[number] = s[number];
issearched[number] = true;//this is where it always crashes even though the ide says issearced has 58 elements and the random number is always smaller than that.
}
else
i--;
}
return newlist;
}
im sure its simple but i can't figure out why index of 8 is outside the range of the array of 58.

Your array newlist (what a confusing name) has no space to store anything.
This line
string[] newlist = {};
declares the array but without setting the space to store any element, so when you try to use the indexer on it you get the exception.
I suggest to use a different approach to find 30 strings from your passed array.
Using a List<string> and continue to add to this list until you have 30 elements in the list
static string[] newlist(string[] s)
{
List<string> selectedElements = new List<string>();
bool[] issearched = new bool[s.Length];
Random callorder = new Random();
while(selectedElements.Count < 30))
{
int number = callorder.Next(0, s.Length);
if (!issearched[number])
{
selectedElements.Add(s[number]);
issearched[number] = true;
}
}
return selectedElements.ToArray();
}
If you prefer to use arrays as from your method then a couple of fixing is required to your code
static string[] newlist(string[] s)
{
string[] newlist = new string[30];
bool[] issearched = new bool[s.Length];
Random callorder = new Random();
for (int i = 0; i < 30; i++)
{
int number = callorder.Next(0, s.Length);
if (issearched[number] == false)
{
newlist[i] = s[number];
issearched[number] = true;
}
else
i--;
}
return newlist;
}
The newlist array is declared to have space to store 30 elements
The for loops for 30 times (not 31 as from your current code)
The newlist should use as indexer the value of the variable i

I believe you're actually crashing here:
newlist[number] = s[number];
Replace
string[] newlist = {};
With
string[] newlist = new string[s.Length];
Your newlist size is 0 elements, nowhere are you allocating enough space for it.
Also your program will go into an infinite loop if the input size is less than 31 elements.

Related

I want to create an array of scene indexes and use it, when i need. The problem is that i don't know how to create the array itself

I did this
public int[] sceneIndex;
public Text[] texts;
IEnumerator ChoosingModes()
{
string[] modes = new string[] { "Cocks", "Tanks", "Cars" };
sceneIndex = new int[] { };
for (int i = 0; i < 5; i++)
{
int x = Random.Range(0, modes.Length);
texts[i].text = modes[x];
sceneIndex[i] = x + 3;
yield return new WaitForSeconds(0.75f);
}
}
It obviously doesn't work, what to do with my in array named 'sceneIndex'?
When you do sceneIndex = new int[] { };, you're locking the length of the length of sceneIndex to 0. Instead, try either sceneIndex = new int[number or scenes]; (locking the length of sceneIndex to the number of scenes you have) or just doing nothing. Since the array is public, you can set the values in the inspector and you won't have to define it in the code.

get random 8 element values from array string without duplicated element

I have a string array with length is 100.
I want to get random 8 elements among 100 element without duplicated elements in C#.
Please help me.
I appreciate it.
I just use:
for (int i = 0; i < 8; i++)
{
work with 8 values here
}
Above code just performs to get 8 first values not 8 random values.
Easy way:
var random = new Random();
var randomValues = arr.OrderBy(x => random.Next()).Take(8)
Effective way: use Fisher–Yates shuffle. Jon Skeet provided the implementation here.
Here is the code.
Explanation
Randomly generate numbers between 0 - 99.
Using a hashset to keep track of indices that I am picking. If the index is present in hashset then it means that the value has already been selected, so skip it.
If the values in array are not unique, then in hashset instead of tracking index track values.
public List<string> GetRandomElements(string[] givenArray)
{
if(givenArray == null || givenArray.Length == 0)
{
throw new ArgumentNullException("givenArray");
}
var rand = new Random();
var randomArray = new List<string>();
var indexTracker = new HashSet<int>();
while(randomArray.Count < 8)
{
var nextIndex = rand.Next(0, givenArray.Length);
if(indexTracker.Contains(nextIndex))
{
continue;
}
randomArray.Add(givenArray[nextIndex]);
indexTracker.Add(nextIndex);
}
return randomArray;
}
Note I assumed here there was no constraint on using extra memory for hashset (because there will be max of 8 members only). If that is the constraint, then another way could be, split the index into 8 parts. So pick first index between 0-8, next index between 9-16 and so one. This way you will get unique numbers.
You can use generics and simply do:
static T[] GetRandomRange<T>(T[] arr, int length)
{
var r = new Random();
List<T> elementsList = new List<T>();
for (; elementsList.Count < length; )
{
T el = arr[r.Next(0, arr.Length)];
if (!elementsList.Contains(el)) elementsList.Add(el);
}
return elementsList.ToArray();
}
Use it like :
int[] arr ...
int[] newArray = GetRandomRange(arr, 8);
MyClass[] arr2...
MyClass[] newArray2 = GetRandomRange(arr2, 5);
It's pretty straightforward, just pass it to HashSet<string> and apply the following logic:
var mySet = new HashSet<string>(myList);
var myList = new List<string>();
var random = new Random();
for (int i = 0; i < 8; i++)
{
int randValue = random.Next(0, mySet.Count());
string randSetValue = mySet.ElementAt(randValue);
myList.Add(randSetValue );
mySet.Remove(randSetValue);
}

passing arrays in c#

Hi i am working on Grade Calculation. My problem here is if the length of string array is longer that int array it works skipping the last 2 grades.
ex:
int[] unit = new int[] {1,-3,3,4};
string[] letter_grade = new string[] {"A", "B","B","W","D","F"};
but if length of int array longer than that of string array its not working its throwing error Index was outside the bounds of the array.
int[] unit = new int[] {1,-3,3,4,5,6,7};
string[] letter_grade = new string[] {"A", "B","B"};
so my question how do i make it work for both??
int length = unit.Length;
int no_units = length;
double totalGrade_Points = 0.0;
int totalno_units = 0;
totalGPA = 0;
for (int i = 0; i < unit.Length; i++)
{
entrygot = findGpaListentry(letter_grade[i]); //Index was outside the bounds of the array.
if (entrygot != null)
{
//some code calculation
}
}
For array indexing you must have starting and stopping condition defined very well. For accessing two arrays either they must be equal or they are compared under certain valid conditions. Have a look at this:
for(int i=0;i<unit.length;i++){
entrygot = findGpaListentry(letter_grade[i]);// only if letter_grade is valid under all values of i i.e unit.length
}
// either you have to check as if;
if(lenght_of_letter_grade < i-1)
//then access
entrygot = findGpaListentry(letter_grade[i]);
You can't just check if the array item is null, because you would be out of the bounds of the array and you will get an exception before the null check occurs.
I would check the length of the array on each iteration...
for (int i = 0; i < unit.Length; i++)
{
if (currentArray.Length < i - 1) { break; }
// other code...
}
I think in your case, the number of elements will never be large hence performance wont be an issue. So I think you should be using a List instead of an array. With an array you will have to be insert checks each time some logic changes or you add other functionalities.
foreach loop is best for your scenerio.
foreach (string s in letter_grade)
{
entrygot = findGpaListentry(s);
if (entrygot != null)
{
//some code calculation
}
}

only return random number when it is unique

My brain is melting today and i cannot think how to do this simple bit of code. numberList is a string of numbers seperated by commas like '2, 34, 10' etc.. when i request a random number i need to check if the string has the number, if it does i want to keep requesting a random number until the random number is definitely not in the string. i cant think what kind of loop i would do to get this to work:
Random r = new Random();
public int RandomPos(int max) {
int i;
do {
i = r.Next(max) + 1;
}
while (!numberList.Contains(i.ToString()));
return i;
}
I'll just explain in text instead of code because I'm too lazy to write the code right now:
Use String.Split to break your list into an array, then (if you need to) parse it into integers.
Use Enumerable.Range(0, max).ToArray() to create a list of all the numbers you could select.
Subtract the first list from the second.
Randomly select an element from the final list.
This has the benefit that you don't need to keep picking things randomly and retrying in a potentially-infinite-but-not-really-in-practice loop.
edit: here's some code
string[] invalid = numberList.Split(", ");
var list = Enumerable.Range(0, max).Where(x => !invalid.Contains(x.ToString())).ToArray();
return list[r.Next(list.Count)];
Remove the !
do
{
i = r.Next(max) + 1;
}
while (numberList.Contains(i.ToString()));
Try it with this:
static string invalidNumbers = "0,1,2,3,4,5";
static Random random = new Random();
static int Randomize()
{
var randomInt = random.Next(0, 10);
if (!invalidNumbers.Split(',').Contains(randomInt.ToString()))
{
return randomInt;
}
else
{
return Randomize();
}
}
Providing a simple answer, you don't need Split(). This assumes no spaces between numbers, modify accordingly:
String modifiedNumberList = "," + numberList + ",";
do {
i = r.Next(max) + 1;
}
while (modifiedNumberList.Contains("," + i.ToString() + ","));
edit: I believe BrokenGlass is also right, you shouldn't have the "!", removed from my solution.
Maybe this is what you want? I used a regular while instead since I think they are easier to read, and the only thing I think you get wrong was the !.
public int RandomPos(int max) {
int i = r.Next(max);
var intList = numberList.Split(',').ToDictionary<string,int>((n) => int.Parse(n));
while(intList.Contains(i))
{
i = r.Next(max);
}
return i;
}
Assuming I need to split the numberList first to if they are in a string. That would make the third row look like:
A modification of #Dave's reply:
static string invalidNumbers = "0,1,2,3,4,5";
static Random random = new Random();
static int Randomize()
{
var randomInt = random.Next(0, 10);
var splitString = invalidNumbers.Split(',');
while (splitString.Contains(randomInt.ToString()))
{
randomInt = random.Next(0, 10);
}
return randomInt;
}
A couple ways to improve this:
1) Use a List<int> or something instead of a string to make your life easier
2) if max is small (say <1000 or something) generate the list of all possible values, order them randomly, and return numbers in sequence from that list.
As the number of "used" numbers approaches "max" you could end up in a very long loop before you get an unused number. For values of max over a couple hundred, this could actually be of consequence. This may or may not be a problem in your situation.
This code will cover all cases:
"1,2,3,4,5"...
"1, 2, 3,4,5"...
private static int GetRandomNumber(string existingNumbers, int max)
{
string[] existingNumbersArray = existingNumbers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
List<string> existingNumbersList = new List<string>();
foreach (string number in existingNumbersArray)
{
existingNumbersList.Add(number.Trim());
}
while (true)
{
Random rnd = new Random();
int value = rnd.Next(max);
if (!existingNumbersList.Contains(value.ToString()))
{
return value;
}
}
}
You can even take out this part:
string[] existingNumbersArray = existingNumbers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
List<string> existingNumbersList = new List<string>();
foreach (string number in existingNumbersArray)
{
existingNumbersList.Add(number.Trim());
}
so it will not be called each time you call GetRandomNumber function.
My addition to all the other answers..
const string invalidNumbers = "0,1,2,3,4,5";
Random random = new Random();
int value = 0;
List<int> tmpList = new List<int>();
foreach (var x in invalidNumbers.Split(','))
{
tmpList.Add(Int32.Parse(x));
}
do
{
value = random.Next(0, 10);
}
while (tmpList.Contains(value));
return value
Edit: missunderstood the question for the first post, anyway, here is a recursive solution.
It seems better to keep the numbers in a List, but if it is required to follow the format you asked, here it is:
const int MAX_ATTEMPTS = 10;
Random r = new Random();
string nlist = "2, 34, 10";
public int RandomPos(int max_val)
{
List<string> used = nlist.Replace(" ","").Split(',').ToList();
return _RandomPos(MAX_ATTEMPTS, max_val, used);
}
private int _RandomPos(int tl, int max, List<string> used)
{
if (tl <= 0)
throw new Exception("Could not generate random number. Too many tries.");
else
{
int rnum = r.Next(max);
if (!used.Contains(rnum.ToString()))
{
nlist += ", " + rnum.ToString();
return rnum;
}
else
return _RandomPos(tl - 1, max, used);
}
}
I realize there are a lot of entries, but I don't see any with some decent error checking. That being said, this will offer a few things:
Won't waste any effort when there's nothing to disqualify
Will only select from a range of possible choices
Will flag -1 if a number can't be chosen within the max range and not in the disqualifying list
So here goes:
public int RandomPos(int max)
{
// compile the list of numbers we need to disqualify
List<int> disqualified = numberList.Split(new[]{',',' '},StringSplitOptions.RemoveEmptyEntries).Select(n => int.Parse(n)).ToList();
// Nothing to check against, save the CPU cycles
if (disqualified.Count == 0)
return (new Random(DateTime.Now.Millisecond)).Next(max) + 1;
// make a list of everything that's possible for a choice
List<int> valid = Enumerable.Range(0, max).Where(r => !disqualified.Contains(r)).ToList();
// return either a valid result, or -1 if there are no valid results
return (valid.Count == 0 ? -1 : valid[(new Random(DateTime.Now.Millisecond)).Next() % valid.Count]);
}
.Split will do the work, the following code will work as well, just for fun (replace the line while (!numberList.Contains(i.ToString())); in your code instead of checking i.ToString() check ","+i.ToString()+"," PLUS the beginning and ending. You need to adjust it if you have a space after ","):
while (!numberList.StartsWith(i.ToString()+",")&&
!numberList.Contains(","+i.ToString()+",")&&
!numberList.EndsWith(","+i.ToString()));
// if numberList is large then use HashSet<int> rather than a plain int[] array
int[] nums = numberList.Split(new[] { ',', ' ' },
StringSplitOptions.RemoveEmptyEntries)
.Select(int.Parse)
.ToArray();
int i;
while (nums.Contains(i = r.Next(max) + 1));
return i;
(You should also add a check to ensure that you don't end up in an infinite loop if/when numberList contains all the possible values that might be produced by the rng.)

Adding values to a C# array

Probably a really simple one this - I'm starting out with C# and need to add values to an array, for example:
int[] terms;
for(int runs = 0; runs < 400; runs++)
{
terms[] = runs;
}
For those who have used PHP, here's what I'm trying to do in C#:
$arr = array();
for ($i = 0; $i < 10; $i++) {
$arr[] = $i;
}
You can do this way -
int[] terms = new int[400];
for (int runs = 0; runs < 400; runs++)
{
terms[runs] = value;
}
Alternatively, you can use Lists - the advantage with lists being, you don't need to know the array size when instantiating the list.
List<int> termsList = new List<int>();
for (int runs = 0; runs < 400; runs++)
{
termsList.Add(value);
}
// You can convert it back to an array if you would like to
int[] terms = termsList.ToArray();
Edit: a) for loops on List<T> are a bit more than 2 times cheaper than foreach loops on List<T>, b) Looping on array is around 2 times cheaper than looping on List<T>, c) looping on array using for is 5 times cheaper than looping on List<T> using foreach (which most of us do).
Using Linq's method Concat makes this simple
int[] array = new int[] { 3, 4 };
array = array.Concat(new int[] { 2 }).ToArray();
result
3,4,2
If you're writing in C# 3, you can do it with a one-liner:
int[] terms = Enumerable.Range(0, 400).ToArray();
This code snippet assumes that you have a using directive for System.Linq at the top of your file.
On the other hand, if you're looking for something that can be dynamically resized, as it appears is the case for PHP (I've never actually learned it), then you may want to use a List instead of an int[]. Here's what that code would look like:
List<int> terms = Enumerable.Range(0, 400).ToList();
Note, however, that you cannot simply add a 401st element by setting terms[400] to a value. You'd instead need to call Add() like this:
terms.Add(1337);
By 2019 you can use Append, Prepend using LinQ in just one line
using System.Linq;
and then in NET 6.0:
terms = terms.Append(21);
or versions lower than NET 6.0
terms = terms.Append(21).ToArray();
Answers on how to do it using an array are provided here.
However, C# has a very handy thing called System.Collections
Collections are fancy alternatives to using an array, though many of them use an array internally.
For example, C# has a collection called List that functions very similar to the PHP array.
using System.Collections.Generic;
// Create a List, and it can only contain integers.
List<int> list = new List<int>();
for (int i = 0; i < 400; i++)
{
list.Add(i);
}
Using a List as an intermediary is the easiest way, as others have described, but since your input is an array and you don't just want to keep the data in a List, I presume you might be concerned about performance.
The most efficient method is likely allocating a new array and then using Array.Copy or Array.CopyTo. This is not hard if you just want to add an item to the end of the list:
public static T[] Add<T>(this T[] target, T item)
{
if (target == null)
{
//TODO: Return null or throw ArgumentNullException;
}
T[] result = new T[target.Length + 1];
target.CopyTo(result, 0);
result[target.Length] = item;
return result;
}
I can also post code for an Insert extension method that takes a destination index as input, if desired. It's a little more complicated and uses the static method Array.Copy 1-2 times.
Based on the answer of Thracx (I don't have enough points to answer):
public static T[] Add<T>(this T[] target, params T[] items)
{
// Validate the parameters
if (target == null) {
target = new T[] { };
}
if (items== null) {
items = new T[] { };
}
// Join the arrays
T[] result = new T[target.Length + items.Length];
target.CopyTo(result, 0);
items.CopyTo(result, target.Length);
return result;
}
This allows to add more than just one item to the array, or just pass an array as a parameter to join two arrays.
You have to allocate the array first:
int [] terms = new int[400]; // allocate an array of 400 ints
for(int runs = 0; runs < terms.Length; runs++) // Use Length property rather than the 400 magic number again
{
terms[runs] = value;
}
int ArraySize = 400;
int[] terms = new int[ArraySize];
for(int runs = 0; runs < ArraySize; runs++)
{
terms[runs] = runs;
}
That would be how I'd code it.
C# arrays are fixed length and always indexed. Go with Motti's solution:
int [] terms = new int[400];
for(int runs = 0; runs < 400; runs++)
{
terms[runs] = value;
}
Note that this array is a dense array, a contiguous block of 400 bytes where you can drop things. If you want a dynamically sized array, use a List<int>.
List<int> terms = new List<int>();
for(int runs = 0; runs < 400; runs ++)
{
terms.Add(runs);
}
Neither int[] nor List<int> is an associative array -- that would be a Dictionary<> in C#. Both arrays and lists are dense.
You can't just add an element to an array easily. You can set the element at a given position as fallen888 outlined, but I recommend to use a List<int> or a Collection<int> instead, and use ToArray() if you need it converted into an array.
If you really need an array the following is probly the simplest:
using System.Collections.Generic;
// Create a List, and it can only contain integers.
List<int> list = new List<int>();
for (int i = 0; i < 400; i++)
{
list.Add(i);
}
int [] terms = list.ToArray();
one approach is to fill an array via LINQ
if you want to fill an array with one element
you can simply write
string[] arrayToBeFilled;
arrayToBeFilled= arrayToBeFilled.Append("str").ToArray();
furthermore, If you want to fill an array with multiple elements you can use the
previous code in a loop
//the array you want to fill values in
string[] arrayToBeFilled;
//list of values that you want to fill inside an array
List<string> listToFill = new List<string> { "a1", "a2", "a3" };
//looping through list to start filling the array
foreach (string str in listToFill){
// here are the LINQ extensions
arrayToBeFilled= arrayToBeFilled.Append(str).ToArray();
}
Array Push Example
public void ArrayPush<T>(ref T[] table, object value)
{
Array.Resize(ref table, table.Length + 1); // Resizing the array for the cloned length (+-) (+1)
table.SetValue(value, table.Length - 1); // Setting the value for the new element
}
int[] terms = new int[10]; //create 10 empty index in array terms
//fill value = 400 for every index (run) in the array
//terms.Length is the total length of the array, it is equal to 10 in this case
for (int run = 0; run < terms.Length; run++)
{
terms[run] = 400;
}
//print value from each of the index
for (int run = 0; run < terms.Length; run++)
{
Console.WriteLine("Value in index {0}:\t{1}",run, terms[run]);
}
Console.ReadLine();
/*Output:
Value in index 0: 400
Value in index 1: 400
Value in index 2: 400
Value in index 3: 400
Value in index 4: 400
Value in index 5: 400
Value in index 6: 400
Value in index 7: 400
Value in index 8: 400
Value in index 9: 400
*/
If you don't know the size of the Array or already have an existing array that you are adding to. You can go about this in two ways. The first is using a generic List<T>:
To do this you will want convert the array to a var termsList = terms.ToList(); and use the Add method. Then when done use the var terms = termsList.ToArray(); method to convert back to an array.
var terms = default(int[]);
var termsList = terms == null ? new List<int>() : terms.ToList();
for(var i = 0; i < 400; i++)
termsList.Add(i);
terms = termsList.ToArray();
The second way is resizing the current array:
var terms = default(int[]);
for(var i = 0; i < 400; i++)
{
if(terms == null)
terms = new int[1];
else
Array.Resize<int>(ref terms, terms.Length + 1);
terms[terms.Length - 1] = i;
}
If you are using .NET 3.5 Array.Add(...);
Both of these will allow you to do it dynamically. If you will be adding lots of items then just use a List<T>. If it's just a couple of items then it will have better performance resizing the array. This is because you take more of a hit for creating the List<T> object.
Times in ticks:
3 items
Array Resize Time: 6
List Add Time: 16
400 items
Array Resize Time: 305
List Add Time: 20
I will add this for a another variant. I prefer this type of functional coding lines more.
Enumerable.Range(0, 400).Select(x => x).ToArray();
You can't do this directly. However, you can use Linq to do this:
List<int> termsLst=new List<int>();
for (int runs = 0; runs < 400; runs++)
{
termsLst.Add(runs);
}
int[] terms = termsLst.ToArray();
If the array terms wasn't empty in the beginning, you can convert it to List first then do your stuf. Like:
List<int> termsLst = terms.ToList();
for (int runs = 0; runs < 400; runs++)
{
termsLst.Add(runs);
}
terms = termsLst.ToArray();
Note: don't miss adding 'using System.Linq;' at the begaining of the file.
This seems like a lot less trouble to me:
var usageList = usageArray.ToList();
usageList.Add("newstuff");
usageArray = usageList.ToArray();
Just a different approach:
int runs = 0;
bool batting = true;
string scorecard;
while (batting = runs < 400)
scorecard += "!" + runs++;
return scorecard.Split("!");
int[] terms = new int[400];
for(int runs = 0; runs < 400; runs++)
{
terms[runs] = value;
}
static void Main(string[] args)
{
int[] arrayname = new int[5];/*arrayname is an array of 5 integer [5] mean in array [0],[1],[2],[3],[4],[5] because array starts with zero*/
int i, j;
/*initialize elements of array arrayname*/
for (i = 0; i < 5; i++)
{
arrayname[i] = i + 100;
}
/*output each array element value*/
for (j = 0; j < 5; j++)
{
Console.WriteLine("Element and output value [{0}]={1}",j,arrayname[j]);
}
Console.ReadKey();/*Obtains the next character or function key pressed by the user.
The pressed key is displayed in the console window.*/
}
/*arrayname is an array of 5 integer*/
int[] arrayname = new int[5];
int i, j;
/*initialize elements of array arrayname*/
for (i = 0; i < 5; i++)
{
arrayname[i] = i + 100;
}
To add the list values to string array using C# without using ToArray() method
List<string> list = new List<string>();
list.Add("one");
list.Add("two");
list.Add("three");
list.Add("four");
list.Add("five");
string[] values = new string[list.Count];//assigning the count for array
for(int i=0;i<list.Count;i++)
{
values[i] = list[i].ToString();
}
Output of the value array contains:
one
two
three
four
five
You can do this is with a list. here is how
List<string> info = new List<string>();
info.Add("finally worked");
and if you need to return this array do
return info.ToArray();
Here is one way how to deal with adding new numbers and strings to Array:
int[] ids = new int[10];
ids[0] = 1;
string[] names = new string[10];
do
{
for (int i = 0; i < names.Length; i++)
{
Console.WriteLine("Enter Name");
names[i] = Convert.ToString(Console.ReadLine());
Console.WriteLine($"The Name is: {names[i]}");
Console.WriteLine($"the index of name is: {i}");
Console.WriteLine("Enter ID");
ids[i] = Convert.ToInt32(Console.ReadLine());
Console.WriteLine($"The number is: {ids[i]}");
Console.WriteLine($"the index is: {i}");
}
} while (names.Length <= 10);

Categories

Resources