Iterating generic list using indexes (C#) - c#

I've pretty much switched over to generic types and away from the array types but now and then I need to iterate through something where it is convenient to have indexes like those arrays provide. Generic lists are great because they keep the order of things internally the same as the order of things inserted, they grow dynamically and come with very useful methods but can I jump around like I can with arrays? Could I say, iterate a generic list using a for loop and on certain indexes get the value of past or future indexes without having to iterate over all of the values in between?
Example using an array:
for (int i = 50; i != 0; --i)
{
if (myArray[i] == 1 && i + 5 <= 50)
{
myArray[i + 5] = myArray[i + 5] + 2;
}
}

Yes you can do that with list just like arrays. List have indexers which act similar to array indexer. Did you try it and it not work?
var lists = Enumerable.Range(0, 51).ToList();
for (var i = 50; i != 0; --i)
{
if (lists[i] == 1 && i + 5 <= 50)
{
lists[i + 5] = lists[i + 5] + 2;
}
}

Related

C# Insertion sort List (ascending + descending)

I am developing a game in Unity, c#.
I have a large Vector3 list of 16k elements that has holds x position, y for dic key and z position.
The list gets sorted very often but only 2750 of that list gets sorted and the rest remains unsorted.
Right now I am using linq for a quickstort with orderby:
list = list.OrderBy(x => x).ToList
But it is not the right sort algorithm for my case.
I have no idea how to implement an Insertion sort for a Cector3 list. Just did it with simple arrays. Is there maybe an Insertion sort (ascending and descending) for Vector3 list already in linq?
Well turns out insertion sort is worse.
Thats how I wrote it:
static void sortVec3Array(Vector3[] arrayToSort, int startAt, int stopAt)
{
int i, j;
for (i = startAt+1; i < stopAt; i++)
{
float item = arrayToSort[i].x;
int ins = 0;
for (j = i - 1; j >= 0 && ins != 1;)
{
if (item < arrayToSort[j].x)
{
arrayToSort[j + 1].x = arrayToSort[j].x;
j--;
arrayToSort[j + 1].x = item;
}
else ins = 1;
}
}
}
Came across Tim Sort which is kinda what I need.
I implemented it and it works like a charm. Ms is like 1.4 - 1.9 which is 3 times faster than the .Orderby algorithm and now useable for me.

Finding Highest and Lowest value in Array and removing them to compute an average C#

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.

Remove duplicate entries for 2D List in C#

I'm trying to remove example duplicate entries from this 2D List.
I've already tried using the .Distinct().ToList() method as highlighted in answers for 1D Lists but it doesn't seem to work for me here.
My code so far:
List<List<float>> xyvertices = new List<List<float>>();
xyvertices.Add(new List<float>());
yvertices[0].Add(2);
xyvertices[0].Add(4);
for (int a = 1; a < 6; a++)
{
xyvertices.Add(new List<float>());
xyvertices[a].Add(a+1);
xyvertices[a].Add(a+3);
}
xyvertices = xyvertices.Distinct().ToList();
Console.WriteLine("count:" + xyvertices.Count + "\n");
for (int i =0; i<xyvertices.Count; i++)
{
Console.WriteLine(xyvertices[i][0]);
Console.WriteLine(xyvertices[i][1]);
Console.WriteLine();
}
Console.ReadLine();
The above code runs but nothing changes.
How can I make this work? Thanks
Distinct is comparing the Lists, and as the first two Lists are distinct, even though they contain the same two numbers, they are not Equal.
Your outer List is a list of x,y pairs so rather than code these as arbitrary Lists of floats, you can use a Tuple. For example:
List<(float, float)> xyvertices = new List<(float, float)>();
xyvertices.Add((2, 4));
for (int a = 1; a < 6; a++)
{
xyvertices.Add((a+1,a+3));
}
xyvertices = xyvertices.Distinct().ToList();
Console.WriteLine("count:" + xyvertices.Count + "\n");
for (int i = 0; i < xyvertices.Count; i++)
{
Console.WriteLine(xyvertices[i]);
Console.WriteLine();
}
You can use Linq GroupBy and gruop by first and second element as follows :
xyvertices = xyvertices.GroupBy(x=>new {first= x[0],second= x[1] })
.Select(x=>new List<float> { x.Key.first, x.Key.second })
.ToList();
Output :
count:5
2
4
3
5
4
6
5
7
6
8

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.

Remove from list by index when index is not contained in another list

Is there a way to make this code more efficient ?
if (includeRows != null && includeRows.Count > 0)
{
for (int i = aList.Count - 1; i >= 0; i--)
{
if (!includeRows.Exists(j => j == (i + 1)))
{
aList.RemoveAt(i);
includeRows.Remove(i + 1);
}
}
}
This is what i did , the aList contains objects not integers , so need the index of the object in the list.Not sure if the includeRows.Remove() would make it less or more efficient, includeRows was just changed to a HashSet.
for (int i = aList.Count - 1; i >= 0; i--) {
if (!includeRows.Contains(i + 1) )
{
aList.RemoveAt(i);
// includeRows.Remove(i + 1);
}
}
Building on p.s.w.g's answer, I would do:
HashSet<int> includeRowsFaster = new HashSet<int>(includeRows);
aList.RemoveAll(i => !includeRowsFaster.Contains(i + 1));
for most efficient performance and readibility. Looking for an element in includeRows is an O(n) complexity operation. You can reduce it significantly to O(log(n)) by using a hashset instead of a vector (array or list) implementation.
See this for a discussion on Hashset vs. List performance : https://stackoverflow.com/a/10762995/390330
Here's an easy way with Linq's Intersect method:
aList = aList.Intersect(includeRows).ToList();
But for better performance you can use RemoveAll instead
aList.RemoveAll(i => !includeRows.Exists(j => j == (i + 1));
aList = aList.Intersect(includeRows).ToList<int>();

Categories

Resources