I need to create an Array with Linked list capacities.
Basically, I need a static index based list (like array), but with the possibility to get next and previous field (and easily loop back and forward through list, like with linked list).
Note: Array is 2 dimensional. I use a custom class as array values. So I can set previous and next property for each instance.
Is there a built in C# collection for this? If not, any suggestions on how to create a very simple version of this? (I already have a version of this, consisting of 2 methods. One that loops forward to set the previous field, and one to loop backwards that set the next field, but it's still to messy).
Thanks in advance
EDIT:
The problem is my use of 2dimensional array. If loop through my array:
for (byte x = 0; x < Grid.GetLength(0); x++)
{
for (byte y = 0; y < Grid.GetLength(1); y++) /
{
//At certain point, I need to get the previous field. I can do:
if (y != 0)
{
y -= 2; //-2 because I will y++ in for. Already getting messy
}
else
{
//What if y == 0? Then I can't do y--. I should get max y and do x-- to get previous element:
y = (byte)(Grid.GetLength(1) - 1); //to get max value y
x--;
}
}
}
There is a built-in LinkedList<T> class.
But from your description why wouldn't an array work? It's static, and index-based, and you can easily get the next and previous element by incrementing / decrementing the index. It's hard to see exactly what you need from your code, but I'd like to point out that you can easily enumerate over a multi-dimensional array with:
var arry = new int[2,3];
foreach(var item in arry)
{
...
}
So you might be able to combine this with a Stack<T> structure (push items on the stack and pop them off to get the previous).
Alternatively, you can turn the array into a LinkedList directly.
var list = new LinkedList(arry.Cast<int>()); // flattens array
Or to preserve the indexes from the original array and still loop through the values as a linked list use:
var list = new LinkedList(arry.Cast<int>.Select((item, i) => new
{
Item = item,
Index1 = i % arry.GetLength(1),
Index2 = i / arry.GetLength(0)
}));
var node = list.First;
while(node.Next != null)
{
Console.WriteLine("Value # {1}, {2}: {0}", node.Value.Item, node.Value.Index1, node.Value.Index2);
// on some condition move to previous node
if (...)
{
node = node.Previous;
}
else
{
node = node.Next;
}
}
No, you don't. Instead of abandoning traditional arrays in lieu of "smart linked node arrays" which is what it seems like you're heading towards, try just adding a couple variables in your loop body:
byte x_len = Grid.GetLength(0);
byte y_len = Grid.GetLength(1);
byte prev_x, next_x, prev_y, next_y;
for (byte x = 0; x < x_len; ++x)
{
prev_x = x == 0? x_len - 1 : x - 1;
next_x = x == x_len - 1? 0 : x + 1;
for (byte y = 0; y < y_len; ++y)
{
prev_y = y == 0? y_len - 1 : y - 1;
next_y = y == y_len - 1? 0 : y + 1;
// here, you have access to the next and previous
// in both directions, satisfying your requirements
// without confusing your loop variables.
}
}
Related
I am trying to write code that finds the lowest and highest values stored in an array and then removes them from the array to compute an average.
Currently I have written code to produce the average of all numbers in the array but I need to change that once I figure out how to remove Highest and lowest value.
Code I have:
private void HighAndLow()
{
try
{
int[] HighAndLowGrade;
int[] highest = HighAndLowGrade.Max();
int lowest = HighAndLowGrade.Min();
}
catch
{
MessageBox.Show("HighAndLow Method failed");
}
}
//find average without highest and lowest values
private void ComputeMean()
{
double total = 0;
for (int index = 2; index < 9; index ++)
{
total += double.Parse(lineContent[index]);
}
averageTestScore = total / 7;
}
This should work from what I have tested so far.
int[] numberArray = new int[] {1,2,5,9,5,2};
double answer = 0;
var ignoreList = new List<decimal>() {
numberArray.Max(),
numberArray.Min()
};
var cleanList = numberArray.Where(x => !ignoreList.Contains(x));
answer = cleanList.Any() ? cleanList.Average() : 0;
This only requires one iteration through the collection:
public double ComputeAdjustedMean(IEnumerable<int> items)
{
int total = 0;
int count = 0;
int min = int.MaxValue;
int max = int.MinValue;
foreach(int item in items)
{
count++;
total += item;
if (item < min) min = item;
if (item > max) max = item;
}
if (count <= 2) // not enough items
{
// do something here
}
return (total - (min + max)) / (double)(count - 2);
}
Try this using bubble sorting algorithm-
static void Main(string[] args)
{
int[] array = { 12, 6, 34, 23, 89 };
int temp;
for (int i = 0; i <= array.Length - 2; i++)
{
if (array[i] > array[i + 1])
{
temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
}
}
array = array.Skip(1).SkipLast(1).ToArray();
Console.WriteLine((array.Sum()) / (array.Length));
Console.Read();
}
If you have an array of values then you can do this neat LINQ query:
var average_skip_min_and_max =
values
.OrderBy(x => x)
.Skip(1)
.Take(values.Length - 2)
.Average();
I really don't get people when they encounter this kind of questions, they became insanely eager to provide a direct answer. This question is obviously a homework assignment. I'm not saying we don't help OPs but we need to lead them to solutions.
Dear OP,
Do not use the LINQ, yet. I think your instructor is meaning you to learn the sorting algorithms and memory operations. Do some research about them, say, Buble Sort, to sort the array you have. Then it'll be in front of you how to implement and use. After then, you should use the framework provided methods like LINQ's Min() / Max() extension methods.
The approach to your problem is could be like this:
Sort the array ascending.
Get the first element which is now the minimum valued element.
Reallocate a new array but 1 element shorter
Copy your entire array with the current ordered state to newly allocated array but skip the first element when copying, start with next element.
Get the minimum again, but this time search in the newly allocated array and check with the previous minimum
If they are equal go the 3rd operation, if you need to eliminate the repeating minimums ( [1, 1, 2, 3 ...] ), which I think you need to.
If they are not equal, then it means you've found the minimum element of your array and removed all occurences
Now if you repeat the approach to finding the maximum valued element you are done with the elimination process.
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.
I need to check the length of the first dimension of a 2 dimensional list of integers 'centreX1' before following loop:
for (x = 0; x < (int)centreX1[0].Count(); x++)
{
if (BinarySpotsInsideTolerance1[0][x] == 1)
{
AllspotsY.Add(centreY1[0][x]);
AllspotsX.Add(centreX1[0][x]);
AllspotsRLU.Add(RLUSpotsthreshold1[0][x]);
}
}
An error is thrown at centreX1[0].Count() if centreX1 has no members.
You can't count the number of elements in centreX1[0], if centreX1 has no elements.
Make sure centreX1 has elements in it, before trying to access the first one.
if (centreX1.Any()) // or "if (centreX1.Count() > 0)"
{
for (x = 0; x < (int)centreX1[0].Count(); x++)
{
if (BinarySpotsInsideTolerance1[0][x] == 1)
{
AllspotsY.Add(centreY1[0][x]);
AllspotsX.Add(centreX1[0][x]);
AllspotsRLU.Add(RLUSpotsthreshold1[0][x]);
}
}
}
This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 7 years ago.
Unhandled Exception: System.IndexOutOfRangeException: Index was outside of the bounds of the array (at the first if statements)
static int arrayRows = 20;
static int arrayCols = 20;
public void printBoard()
{
int neighbours;
for (y = 0; y < arrayCols; y++)
for (x = 0; x < arrayRows; x++)
{
neighbours = 0;
// Count number of neighbours surrounding live cell
if (parentGen[x-1, y-1] == 1) // top left
neighbours++;
if (parentGen[x-1, y] == 1) // left
neighbours++;
if (parentGen[x-1, y+1] == 1) // bottom left
neighbours++;
if (parentGen[x, y-1] == 1) // middle top
neighbours++;
if (parentGen[x, y+1] == 1) // middle bottom
neighbours++;
if (parentGen[x+1, y-1] == 1) // top right
neighbours++;
if (parentGen[x+1, y] == 1) // right
neighbours++;
if (parentGen[x+1, y+1] == 1) // bottom right
neighbours++;
}
}
The only thing I can think of is that my program is checking coordinates of < 0? How do I go about fixing this?
Your first coordinates are parentGen[-1, -1], this will always throw the exception.
You need to check if the cell you're on has any neighbors to the left, right, top, or bottom. For example, x = 0 has no neighbors to the left and y = 20 has no neighbors to the bottom. You may wish to break this out to other functions, such as HasNeighborsLeft(int x), etc.
edit: sample code
if(x > 0 && y > 0 && parentGen[x - 1, y - 1] == 1)
{
neighbors++;
}
You can factor this out to it's own functions though, and you can wrap this kind of logic around all of the checks that involve x - 1 for example.
You need boundary condition checks on both x and y at top and bottom of their range. You cannot legally index the entire array using +1 and -1 offsets. Break up your check into boundary condition cases where x == 0, x == arrayRows-1 (by not checking the invalid relative offsets here), and then check cases where x+1 and x-1 are always valid in an else. Similarly with y.
You're array goes from 0->21. As well, you're testing values at [-1, -1] and [22, 22]You can fix it by chainging your for statement(s) to
for (int x = 1; x <= arrayCols - 1; x++)
for (int y = 1; y <= arrayRows - 1; y++)
In addition, problems with loops are almost always caused by a small number of cases that you can always check for:
Your for statement a) starts at a lower bound than the array, or b) finishes at a higher one
a) for (int x = -1;
b) for (int x = 0; x <= array.Length
Your code in the loop accesses values outside of your indexer range
for (int x = 0...
array[x-1, ...
Your collection isn't initialized
In this case, your problem 2.
The problem is that you are looking at the previous and next values (-1 and +1) which will obviously go outside the array bounds at either ends of the array.
There are a few options solving this:
Create a bigger array with a dummy 'border' around the edge which you don't use for your board but allows you to use code very similar to that which you have now (with your -1 and +1 previous and next cell logic). (Imagine a chess board that is 10x10 where you are not allowed to play in the outermost squares).
Scatter loads of 'if' statements to check if you're at the first or last item in the array and thus avoid making any array accesses that are invalid.
Create a function to retrieve an item at a particular cell and put conditional logic in this function for dealing with the array bounds.
Personally I would go with the last option, build yourself a function which gets the state of the specified cell, checks that the indices are valid and returns a default value if they are not. For example:
private const int EMPTY_CELL = 0;
private const int INVALID_CELL = EMPTY_CELL; // for now the same, but gives scope to handle separately
private int GetCellState(int row, int column)
{
if (row < 0) return INVALID_CELL;
if (column < 0) return INVALID_CELL;
if (row >= arrayRows) return INVALID_CELL;
if (column >= arrayColumns) return INVALID_CELL;
return parentGen[row, column];
}
It is then simply a matter of swapping your direct accesses to parentGen with calls to the function.
you could start by creating a sequence of only the valid indices and then iterate the combinations of those:
static int arrayRows = 20;
static int arrayCols = 20;
public void printBoard()
{
var sequences = from row in Enumerable.Range(0, arrayRows)
from column in Enumerable.Range(0, arrayCols)
select new
{
Rows = (from xs in new[] { row - 1, row, row + 1 }
where xs >= 0 && xs < 20
select xs),
Columns = (from ys in new[] { column - 1, column, column + 1 }
where ys >= 0 && ys < 20
select ys)
};
//now that we have a sequence with all the needed (valid) indices
//iterate through the combinations of those
var neighbours = (from seq in sequences
from row in seq.Rows
from column in seq.Columns
where row != column && parentGen[row, column] == 1
select 1).Count();
}
I am looping through an array of strings, such as (1/12/1992 apple truck 12/10/10 orange bicycle). The array's length will always be divisible by 3. I need to loop through the array and grab the first 3 items (I'm going to insert them into a DB) and then grab the next 3 and so on and so forth until all of them have been gone through.
//iterate the array
for (int i = 0; i < theData.Length; i++)
{
//grab 3 items at a time and do db insert, continue until all items are gone. 'theData' will always be divisible by 3.
}
Just increment i by 3 in each step:
Debug.Assert((theData.Length % 3) == 0); // 'theData' will always be divisible by 3
for (int i = 0; i < theData.Length; i += 3)
{
//grab 3 items at a time and do db insert,
// continue until all items are gone..
string item1 = theData[i+0];
string item2 = theData[i+1];
string item3 = theData[i+2];
// use the items
}
To answer some comments, it is a given that theData.Length is a multiple of 3 so there is no need to check for theData.Length-2 as an upperbound. That would only mask errors in the preconditions.
i++ is the standard use of a loop, but not the only way. Try incrementing by 3 each time:
for (int i = 0; i < theData.Length - 2; i+=3)
{
// use theData[i], theData[i+1], theData[i+2]
}
Not too difficult. Just increment the counter of the for loop by 3 each iteration and then offset the indexer to get the batch of 3 at a time:
for(int i=0; i < theData.Length; i+=3)
{
var item1 = theData[i];
var item2 = theData[i+1];
var item3 = theData[i+2];
}
If the length of the array wasn't garuanteed to be a multiple of three, you would need to check the upper bound with theData.Length - 2 instead.
Your for loop doesn't need to just add one. You can loop by three.
for(int i = 0; i < theData.Length; i+=3)
{
string value1 = theData[i];
string value2 = theData[i+1];
string value3 = theData[i+2];
}
Basically, you are just using indexes to grab the values in your array. One point to note here, I am not checking to see if you go past the end of your array. Make sure you are doing bounds checking!
This should work:
//iterate the array
for (int i = 0; i < theData.Length; i+=3)
{
//grab 3 items at a time and do db insert, continue until all items are gone. 'theData' will always be divisible by 3.
var a = theData[i];
var b = theData[i + 1];
var c = theData[i + 2];
}
I've been downvoted for this answer once. I'm pretty sure it is related to the use of theData.Length for the upperbound. The code as is works fine because array is guaranteed to be a multiple of three as the question states. If this guarantee wasn't in place, you would need to check the upper bound with theData.Length - 2 instead.
Here is a more general solution:
int increment = 3;
for(int i = 0; i < theData.Length; i += increment)
{
for(int j = 0; j < increment; j++)
{
if(i+j < theData.Length) {
//theData[i + j] for the current index
}
}
}
string[] friends = new string[4];
friends[0]= "ali";
friends[1]= "Mike";
friends[2]= "jan";
friends[3]= "hamid";
for (int i = 0; i < friends.Length; i++)
{
Console.WriteLine(friends[i]);
}Console.ReadLine();