C# Index out of bounds - c#

I am trying to make a linear search where the user inputs a selection of numbers and then they input a random number and the program shows if it is in the list or not.
int[] list = new int[10];
bool found = false;
for (int i = 0; i < 12;)
{
Console.WriteLine("Enter number to be stored.");
list[i] =Convert.ToInt16(Console.ReadLine());
i++;
}
Console.WriteLine("Enter number you want to find.");
int n1 = Convert.ToInt16(Console.ReadLine());
for (int i = 0; i <= 10;)
{
if (list[i] == n1)
{
Console.WriteLine(n1 + " is in the list.");
found = true;
Console.ReadKey();
}
else i++;
}
if (found == false)
{
Console.WriteLine("Element not in this list.");
}
Console.ReadKey();
I am pretty sure that the problem lies in this snippet of code.
int[] list = new int[10];
bool found = false;
for (int i = 0; i < 12;)
{
Console.WriteLine("Enter number to be stored.");
list[i] =Convert.ToInt16(Console.ReadLine());
i++;
}
An array beings with 0 so there are 11 element spaces right?
So when i run it, i go past entering the 10th number and when i enter the 11th, it breaks and says
System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'

Firstly I'd recommend you read up on for loops and arrays in C#.
Secondly you don't want to hardcode the length in the for loop - let the framework do it for you using list.Length. You're seeing the crash because you're trying to assign a value to your array, but the index within your array doesn't exist.
int[] list = new int[10];
bool found = false;
for (int i = 0; i < list.Length; i++)
{
// Do work with list[i]
}

When you say int[10]; you tell it to have 10 entries. They are counting from zero, yes, but that just means that your array has the indices 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
Your loop goes from i = 0 up to i = 11 before it stops because it's no longer smaller than twelve. But the index for the array can at most be 9.
If you set a breakpoint, you should be able to look at the array contents in a debugger. This way, you could also test such things yourself.

It should be i < 10 or i <= 9 if your array only holds 10 objects. The 10 indices will be 0-9.

Related

How to solve an index out of bounds issue, when you have to take into consideration both neighbors of an array's element?

This thing that I'm writing should do the following: get as an input a number, then, that many kids' names, and that many grades. Then, assign each kid a number of coins, so that if their grade is bigger, than their neighbor's, they get more coins and vice versa. What I wrote is this:
string input = Console.ReadLine();
int n = Convert.ToInt32(input);
int i = 0;
string[] names = new string[n];
for (i = 0; i < n; i++)
{
names[i] = Console.ReadLine();
}
string[] gradeText = new string[n];
int[] grades = new int[n];
for (i = 0; i < n; i++)
{
gradeText[i] = Console.ReadLine();
grades[i] = Convert.ToInt32(gradeText[i]);
}
int[] minCoins = { 1, 2, 3 };
int[] coinArray = new int[n];
for (i = 1; i < n - 2; i++)
{
if (grades[0] > grades[1])
{
coinArray[0] = 3;
}
else
{
coinArray[0] = 1;
}
if (grades[i] > grades[i + 1] && grades[i] > grades[i - 1])
{
coinArray[i] = 3;
}
if (grades[i] > grades[i + 1] || grades[i] > grades[i - 1])
{
coinArray[i] = 2;
}
if (grades[i] < grades[i + 1] && grades[i] < grades[i - 1])
{
coinArray[i] = 1;
}
if (grades[n - 1] > grades[n - 2])
{
coinArray[n - 1] = 3;
}
else
{ coinArray[n - 1] = 1; }
}
for (i = 0; i < n; i++)
{
Console.WriteLine(names[i] + " " + coinArray[i]);
}
I know my loop is hella messed up, but any tips on how to fix it would be kindly appreciated!
Others here have already suggested how to deal with index out of bounds issues. So this is slight different approach to solving your problem.
It is very easy to see this as one problem and then try to resolve it all in one place but that isn't always the best solution.
Your for loop is trying to do quite a lot. Each iteration could have many checks to make. In addition you are making checks you have previously made.
Do I have a neighbour to the left.
Do I have a neighbour to the right.
Did I get a better grade than both neighbours.
Did I get a better grade than one neighbour.
Did I lose to both neighbours.
My advice would be to break this down into two separate tasks.
1, To calculate how many neighbours each person got a higher grade than.
string[] names = new string[]{"John", "Paul", "Ringo", "George"};
int[] grades = new[] {3, 4, 3,2};
int[] winnersandloser = new int[4];
for (int i = 1; i < grades.Length; i++) //note starting at position 1 so I dont need to handle index out of bounds inside the for loop
{
if (grades[i] > grades[i - 1])
{
winnersandloser[i]++;
}
else
{
winnersandloser[i - 1]++;
}
}
In the above code you should have an array with these values: {0,2,1,0}
0 = you lost to both neighbours
1 = you beat one neighbour
2 = well done you beat both neighbours
Then using this winnersandlosers array you can calculate how many coins to give each person. I'll leave that for you to do.
Update
If you require different behaviour for the first and last in the list of people you need to add the logic to your code for allocating coins.
An array gives each value and index value, starting from 0. So 0 points to the first value in you array. George is the 4th entry in the array but as the array index starts with 0 the index value is 3, you also get this from arrayname.Length - 1
So now when looping through the array to allocate coins we can add a check for the first and last positions in the array.
//allocating coins
for (int i = 0; i < winnersandloser.Length; i++)
{
if (i == 0 || i == winnersandloser.Length - 1)
{
//allocating rules for first and last
}
else
{
//allocating rules for everyone else
}
}
One common way to approach this kind of issue is to oversize your array by as many elements as you need to look ahead/look behind. Place you real elements in the "middle"1 of this array and suitable dummy values into the elements at the start/end that don't correspond to real entries. You pick the dummy values such that the comparisons work out how you need them to (e.g. often you'll put int.MinValue in the dummy elements at the start and int.MaxValue in the dummy elements at the end).
You then just enumerate the real elements in the array, but all of your computed look aheads/look behinds still correspond to valid indexes in the array.
1Sometimes you'll have uneven look ahead/look behind requirements so it may not be the true middle. E.g. say you need to be able to look behind one element and ahead 3 elements, and you want to process 20 elements. You then create an array containing 24 entries, put dummy values at index 0, 21, 22 and 23, and populate your real elements into indexes 1 - 20.

Array.IndexOf vs. value of given index issue

I'm trying to loop through a given array and find how many duplicate values I have inside it. It works by going through a nested loop checking all elements of the array against each other and making sure it doesn't rise the counter if it's on the same index. But the problem is, it never counts up!
Now it's either I don't understand the concept of valueOf vs indexOf or I'm just completely lost.
int[] myArr = new int[] { 10, 5, 5 };
int counter = 0;
for (int i = 0; i < myArr.Length; i++)
{
for (int j = 0; j < myArr.Length; j++)
{
if (Array.IndexOf(myArr, myArr[i]) == Array.IndexOf(myArr, myArr[j]))
{
continue;
}
else if (myArr[i] == myArr[j])
{
counter++;
}
}
}
Console.WriteLine("There are {0} repeating values in the array.", counter);
// Output: There are 0 repeating values in the array.
Array.IndexOf searches for the first occurrence of the value in the array.
It looks like in your example you are trying to use it to make sure you're not comparing the same position in the array. In which case you could just replace that condition with if(i == j)
Going along with the other answers/comments stating the Array.IndexOf is not the correct approach to this problem, and not exactly sure if you're allowed to use LINQ, but that is by far a better approach, especially using the GroupBy method.
I have created a dotnetfiddle for you to show what I am doing.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
int[] myArr = new int[] { 10, 5, 5, 3, 3, 3 };
// int counter = 0; - now this is no longer needed
var numbersThatAreDuplicates = myArr.GroupBy(x => x).Where(x => x.Count() > 1).Select(x => new { number = x.Key, countOfNumber = x.Count()}).ToList();
Console.WriteLine("There are {0} repeating values in the array.", numbersThatAreDuplicates.Count);
foreach (var item in numbersThatAreDuplicates)
{
Console.WriteLine(item.number + " repeats itself " + item.countOfNumber + " times.");
}
}
}
// Output
// There are 2 repeating values in the array.
// 5 repeats itself 2 times.
// 3 repeats itself 3 times.
As you can see, via the GroupBy method, you can find out how many numbers are repeating, as well as what the actual numbers are along with the number of occurrences that the actual number repeats itself in 1 line of code. Much cleaner, and efficient than using nesting for loops, but again I am not sure of what your limitations are.
I hope this helps.
You don't need to use the Array.IndexOf() function.
for example:
int[] myArr = new int[] { 10, 5, 5, 5};
int counter = 0;
List<int> dups = new List<int>();
for (int i = 0; i < myArr.Length; i++)
{
for (int j = 0; j < myArr.Length; j++)
{
if (i != j && myArr[i] == myArr[j] && !dups.Contains(i))
{
dups.Add(j);
counter++;
}
}
}
Console.WriteLine("There are {0} repeating values in the array.", counter);
// Output: There are 2 repeating values in the array.

In my class i have to creating a method to find multiple maximum numbers in an array C#

In my class i have to create a method that will find multiple maximum numbers within an array. the user will input how many maximum numbers they are wanting and then the code should display all those numbers. if i select 2 this code will show me the 2 maximum numbers but if im wanting more it just doesnt work. i was trying to search the array for the maximum number and then have it display the outcome and then change that element to 0 and than repeat the loop until it hits that number (userinput). im soo frustrated can someone help me please
public static int FindingMaxNum(int[] arr, int max)
{
int userinput;
Console.Write("Enter the number of maximum values: ");
userinput = Convert.ToInt32(Console.Read());
int i = 0;
int c = 0;
for (i = 0; i < arr.Length; i++)
{
if (arr[i] >= max)
{
max = arr[i];
c++;
while (c <= userinput)
{
Console.WriteLine(max);
arr[i] = 0;
break;
}
}
}
return -1;
}
If I understand correctly, you want to get some number of items from an array whose values are greater than all the others in the array.
If so, something like this modified version of your method may do the trick:
public static void WriteMaxNum(int[] arr)
{
if (arr == null)
{
Console.WriteLine("The array is null");
return;
}
if (arr.Length == 0)
{
Console.WriteLine("The array is empty");
return;
}
int count = arr.Length;
int numMaxValues;
// Get number of max values to return from user
do
{
Console.Write("Enter the number of maximum values (1 - {0}): ", count);
} while (!int.TryParse(Console.ReadLine(), out numMaxValues) ||
numMaxValues < 1 ||
numMaxValues > count);
// Output the max values
Console.Write("The {0} max values are: ", numMaxValues);
Console.WriteLine(string.Join(", ", arr.OrderByDescending(i => i).Take(numMaxValues)));
}
Usage
static void Main(string[] args)
{
var myArray = new[] { 1, 9, 4, 8, 2, 5, 0, 7, 6, 3 };
WriteMaxNum(myArray);
Console.Write("\nDone!\nPress any key to exit...");
Console.ReadKey();
}
Output
Simple solution with average complexity O(nlogn):
Sort the array first then print the last N nos.
int[] arr = new int[]{-5,-69,1250,24,-96,32578,11,124};
Array.Sort(arr);
int n=3;
for(int i=arr.Length-1;i>=0 && n>0 ;--i){
n--;
Console.WriteLine(arr[i]);
}
Now coming to your code, there are multiple problems. First there is no need to take 'max' as parameter in your function. Second you are looping only arr.Length times once. There should be nested loop, outer one of which has to run userInput times and inner on has to iterate over all the values. Third you should initialize to extracted value position to minimum value so that the method works for negative numbers too.
Refined code:
for(int i=0;i<userinput;++i){
int max = int.MinValue,pos=-1;
for(int j=0;j<arr.Length;++j){
if(max<arr[j]){
pos = j;
max = arr[j];
}
}
arr[pos] = int.MinValue;
Console.Write(max+",");
}

Sum of Array's Subsets

Im looking for some help with finding subsets of array.
int[] array = { 1,2,3,5,8,10,15,23};
I have to find all subsets of an array. If sum of the subsets elements equal to any number in array then my counter increment. For example: 1+2=3, 2+3=5, 5+8+10=23, 1+2+5=8, 2+3+8+10=23
public static void Main(string[] args)
{
int[] array = { 1, 2, 3, 5, 8, 10, 15, 23 };
int arrayLength = array.Count();
int sum = 0;
int subsetCount = 0;
for (int i = 0; i < arrayLength; i++)
{
for (int j = i + 1; j < arrayLength; j++)
{
sum = array[i] + array[j];
for (int m = j + 1; m < arrayLength; m++)
{
for (int k = 0; k < arrayLength; k++)
{
if (array[k] == sum)
{
subsetCount++;
}
}
sum = array[i] + array[j] + array[m];
}
}
}
Console.WriteLine(subsetCount);
Console.ReadLine();
}
I'm ok with 2-elements and 3-elements of subsets. But 4 and above I can't figured out how to solve it?
Any help would be greatly appreciated
You only need two loops to find the sum of all subsets. The outer loop is the starting point of subsets, and the inner loop is calculating the sums of all subsets from that starting point.
With the first index as starting points the subsets are 1+2, 1+2+3, 1+2+3+5 and so on. As you are only interested in the sum of the subsets you can just add one item after the other to get the sum of the subsets.
Then for each sum loop through the items to check for a match:
int[] array = { 1, 2, 3, 5, 8, 10, 15, 23 };
int subsetCount = 0;
for (int i = 0; i < array.Length; i++) {
int sum = array[i];
for (int j = i + 1; j < array.Length; j++) {
sum += array[j];
for (int k = 0; k < array.Length; k++) {
if (array[k] == sum) {
subsetCount++;
}
}
}
}
Console.WriteLine(subsetCount);
Edit:
I assumed that you meant continuous subsets, but from your examples it seems that you also want non-continuous subsets.
Lets's start with the correct solution:
23 = 15+8, 15+5+3, 15+5+2+1, 10+8+5, 10+8+3+2
15 = 10+5, 10+3+2, 8+5+2
10 = 8+2, 5+3+2
8 = 5+3, 5+2+1
5 = 3+2
3 = 2+1
That gives us 14 different subsets that sums up to an item in the set.
You can count the subsets recursively, only keeping track of the sum and number of items in subsets. You don't need the actual subsets, only to know the sum and that there are at least two items in the subset.
The subsets in a set is the first item combined with all subsets in the rest of the set, plus the subsets in the rest of the set. For example the subsets s() of [1,2,3] is 1,s([2,3]) and s([2,3]).
This gives you:
public static int CountSubsets(int[] arr, int start, int len, int sum) {
int cnt = 0;
if (start < arr.Length) {
if (len >= 1 && arr.Contains(sum + arr[start])) cnt++;
cnt += CountSubsets(arr, start + 1, len + 1, sum + arr[start]);
cnt += CountSubsets(arr, start + 1, len, sum);
}
return cnt;
}
And calling it:
int[] set = { 1, 2, 3, 5, 8, 10, 15, 23 };
Console.WriteLine(CountSubsets(set, 0, 0, 0));
Output:
14
This seems a lot like homework to me. So I will answer in that spirit (i.e. rather than write the code, point you in the right direction).
First, it's not really clear what you mean by "subset". Are you talking about contiguous runs of elements from the array? Or do you literally mean treating the array as an unordered set, from which you examine every possible subset?
The latter is significantly harder than the former. So I'm going to assume the former for the moment.
Then, it seems you really have two different problems:
Find all subsets of the array and sum each one
For a given sum, determine whether it's in the array
The latter is fairly straightforward. If you know these arrays will always be relatively short (and hopefully they will be, otherwise "find all subsets" may take awhile :) ), you can just do a linear search every time you have a new sum to look for.
Alternatively, a more semantically straightforward approach would be to create a HashSet<int> instance once using the members of the array, and then when you want to know if the sum is in the array, just check your set.
For example:
HashSet<int> setOfValues = new HashSet<int>(array);
Then you can just write setOfValues.Contains(sum) to check whether the value held by the variable sum is contained in the array.
As for the first problem, it seems to me that you really should only need two loops:
A loop to iterate on the index of the first element of a subset. I.e. you need to enumerate all subsets, first starting with all subsets that start with element 0, then with all subsets that start with element 1, and so on.
A loop to iterate on the length of the subset. I.e. having determined the starting index for your current group of subsets, now you want to find all the actual subsets: the first has length 1, the second has length 2, and so on up to the maximum possible length (i.e. the length of the array minus the current 0-based starting index value).
Considering for a moment the alternative possibility — that you are treating the array as an unordered set — then it seems to me an obvious, if brute-force approach, would be to generate the subsets recursively.
In that approach, you would again have a loop to enumerate the subset lengths, starting with 1, up to the total length of the original set. Then, given a length, you need to pick all possible subsets.
You can do this recursively:
Given a set, iterate over the elements of the current set (passed in to your recursive method). The current element is the new element of your current subset.
If your current subset is now the correct length, sum it and compare to the original set.
Otherwise, remove the current element from the current set and recurse.
The easiest implementation of the above will create new copies of the current set for each level of recursion, to pass to the method when it calls itself. This way you don't have to worry about one level of recursion interfering with previous levels.
Do note that this is going to be practical only for relatively small initial sets. It won't take very large initial arrays before your computer doesn't have enough time or memory to complete the search of all possible subsets.
First up, you need a method that will return all subsets.
Func<IEnumerable<int>, IEnumerable<IEnumerable<int>>> getAllSubsets = null;
getAllSubsets = xs =>
(xs == null || !xs.Any())
? Enumerable.Empty<IEnumerable<int>>()
: xs.Skip(1).Any()
? getAllSubsets(xs.Skip(1))
.SelectMany(ys => new [] { ys, xs.Take(1).Concat(ys) })
: new [] { Enumerable.Empty<int>(), xs.Take(1) };
So given getAllSubsets(new[] { 1, 2, 3 }) I get:
{ }
{ 1 }
{ 2 }
{ 1, 2 }
{ 3 }
{ 1, 3 }
{ 2, 3 }
{ 1, 2, 3 }
Now's it's easy to compute the result you want.
int[] array = { 1,2,3,5,8,10,15,23};
var result =
getAllSubsets(array)
.Where(ss => array.Contains(ss.Sum()))
.Count();
I get 22.
Using a bit of Linq:
int[] array = {1, 2, 3, 5, 8, 10, 15, 23};
var subsets = new List<IEnumerable<int>>();
int counter = 0;
for (int i = 0; i < array.Length; i++)
{
for (int j = 2; j < array.Length - i; j++)
{
if (array.Contains(array.Skip(i).Take(j).ToList().Sum()))
{
counter++;
}
}
}
Console.WriteLine("Number of subsets:" + counter);
Gives you:
Number of subsets:5

Generate some unique numbers and put into array

I'm trying to create a method that produces 10 unique random numbers, but the numbers are not unique, I get several duplicates! How can I improve the code to work as I want?
int[] randomNumbers = new int[10];
Random random = new Random();
int index = 0;
do
{
int randomNum = random.Next(0, 10);
if (index == 0)
{
randomNumbers[0] = randomNum;
index++;
}
else
{
for (int i = 0; i < randomNumbers.Length; i++)
{
if (randomNumbers[i] == randomNum)
break;
else
{
randomNumbers[index] = randomNum;
index++;
break;
}
}
}
}
while (index <= 9);
foreach (int num in randomNumbers)
System.Console.Write(num + " ");
EDIT 2: I have corrected all errors now, but this code isn't working becuase the numbers are not unique! I have updated my code above to the latest version. I preciate some help to solve this! Thanks!
The simplest way to have this is to have an array of the numbers you want (i.e. 1-10) and use a random shuffling algorithm.
The Fisher-Yates shuffle is the easiest way to do this.
EDIT:
Here's a link to a C# implementation: http://www.dotnetperls.com/fisher-yates-shuffle
random.next(0, 10) returns a random number between 0 and 10. It can happen, that it returns the same number multiple times in a row and it is not guaranteed, that you get every number between 0 and 10 exactly one time, when you call it 10 times.
What you want is a list of numbers, every number is unique, between 0 and 9 (or 1 and 10). A possible solution to this would be something like this:
//Create the list of numbers you want
var list = new List<int>();
for(var x = 0; x < 10; x++)
{
list.Add(x);
}
var random = new Random();
//Prepare randomized list
var randomizedList = new List<int>();
while(list.Length > 0)
{
//Pick random index in the range of the ordered list
var index = random.Next(0, list.Length);
//Put the number from the random index in the randomized list
randomizedList.Add(list[index]);
//Remove the number from the original list
list.RemoveAt(index);
}
Explained in words, this is what you do:
Create the list with all the numbers, that your final list should contain
Create a second empty list.
Enter a loop. The loop continues, as long as the ordered list still has numbers in it.
Pick a random index between 0 and list.Length
Put this random number in the randomized list
Remove the item at the index position from the ordered list.
Like this you create the set of numbers you want to have in your randomized list and then always pick a random entry from the ordered list. With this technique, you can also achieve, that certain values occur multiple time in the list.
I'm not sure if my code compiles against c#, as I currently do not have visual studio running here, but I think the code should be mostly correct.
Something like this?
const int maxNumbers = 10;
List<int> numbers = new List<int>(maxNumbers);
for (int i = 0; i < maxNumbers; i++)
{
numbers.Add(i);
}
Random r = new Random();
while (numbers.Count > 0)
{
int index = r.Next(numbers.Count);
Console.Write("{0} ", numbers[index]);
numbers.RemoveAt(index);
}
Console.WriteLine();
Edit: For any random numbers:
const int maxNumbers = 10;
const int biggestNumbers = 10000;
List<int> numbers = new List<int>(maxNumbers);
Random r = new Random();
while (numbers.Count < maxNumbers)
{
int index = r.Next(biggestNumbers);
if (numbers.IndexOf(index) < 0)
{
numbers.Add(index);
Console.Write("{0} ", index);
}
}
Console.WriteLine();

Categories

Resources