C# Interop loop through values received from a range - c#

How can I loop through the values that are returned from a specified range?
I tried the following code but it returns:
Cannot apply indexing with [] to an expression of type 'System.Array'
var rng = (Excel.Range)sheet.Range[sheet.Cells[3, 2], sheet.Cells[3, 27]];
var wsValues = rng.Cells.Value;
for (var j = 0; j < wsValues.Length; j++)
{
var test = wsValues[j];
}

Its a system array not a 'normal array' (based upon the error). So you should be able to use var test = wsValues.GetValue(1, j); Note this will return an object. So you will have to do a cast to your expected type.
Also note that the 1 in that case is because all your test data has 1 as your first value in your multidimensional array. You can view a multidimensional array as a grid, with an x co-ordinate and a y co-ordinate, so if you wanted to iterate through them properly (as if you were using up multiple columns instead of just one). Then you would do:
for (var x = 1; x <= wsValues.GetLength(0); x++)
{
for (var y = 1; y <= wsValues.GetLength(1); y++)
{
var test = wsValues[x, y];
}
}
In this the GetLength command returns the length of that dimension, so the first one returns the length of how many 'columns' or the maximum x value there are, and the second one returns the maximum y value or how many rows there are.

Related

Table index out of bounds allthough the table is bigger than the index

I'm working on a simple matching game and I want to output a leaderboard, but i get an exception array index out of bounds. In the debug though it says that the table's size is 3 and that both i and j are 0 and 1, which is weird to me becouse that is not out of bounds since the array size is 3. This is my code for sorting the array of objects from biggest to smallest by the highscore, thanks for the help.
for(int i = 0; i<tabUporabnikov.Length-1; i++)
{
for(int j = (i+1); j<tabUporabnikov.Length; j++)
{
if (tabUporabnikov[i].highscore < tabUporabnikov[j].highscore)
{
Uporabnik[] zacasna = new Uporabnik[1];
zacasna[1] = tabUporabnikov[j];
tabUporabnikov[j] = tabUporabnikov[i];
tabUporabnikov[i] = zacasna[1];
}
}
}
it should be zacasna[0]. Aray can have only one value in this case and array starts with index 0. so it should be zacasna[0]. better you declare a variable instead of array because you need to store only value. declare it as Uporabnik zacasna

Check against two separate array values and grabbing the smallest one to insert into a new array the CW new array values

I am working with Arrays and conditionals statements, little lost right now and was hoping for some input.
So, I created two Arrays
int[] one = new int[] {
4160414, 6610574, 2864453, 9352227, -4750937, -3132620, 2208017,
-2226227, -8415856, -9834062, -3401569, 7581671, 8068562, 7520435,
-9277044, -7821114, -3095212, 966785, 6873349, -8441152, -7015683,
-6588326, -282013, 4051534, 9930123, -3093234 };
int[] two = new int[] {
1099626, 6083415, 8083888, -8210392, 2665304, -8710738, -8708241,
8859200, -1255323, 5604634, 2921294, -7260228, 7261646, 1137004,
5805162, 4883369, 8789460, 9769240, 319012, -7877588, -1573772,
5192333, 1185446, 1302131, 4217472, -3471445};
My next step what i was thinking is i am going to have to loop through each array
for (int i = 0; i < one.Length; i++)
{
int xValue = one[i];
for (int j = 0; j < two.Length; j++)
{
int yValue = two[j];
}
}
Now that i have the index of each Array i need to check wether the index of xValue is less than the index of yValue
if (xValue < yValue)
{
// dO SOMETHING HERE
}
if (yValue < xValue)
{
// Do Something HERE
}
Where i am getting confused at, is with C# from my understanding you can not push new values into an Array, it needs to be a new instance of the array and copy?
So i tried doing
if (xValue < yValue)
{
Array.Copy(one, x, 13);
}
if (yValue < xValue)
{
Array.Copy(two, x, 13)
}
Both Arrays have 26 values, so a new array of 13 would need to be created to insert the checked value, but Array.Copy seems to not be working getting an array out of bounds check lower bounds.
I'm just confused on checking the values of both arrays at their index, then grabbing the smallest value of the checked values then taking that small value and inserting it into a new array, then use a foreach-loop to iterate over it and print the values to the console. FacePalm
You can use LINQ's Zip to achieve this:
int[] smallest = one.Zip(two, (o, t) => Math.Min(o,t)).ToArray();
Essentially, Zip will provide both items to the lambda expression, allowing you to combine them how you see fit. In this case, we just choose the minimum and return it.
Try it online
Basically, you need to define the size of the new array when you declare it. Make it the same size as one. Then add the smallest item from one or two on each iteration by comparing the items in each array at index i.
int[] smallest = new int[one.Length];
for (int i = 0; i < one.Length; i++)
{
if (one[i] < two[i])
{
smallest[i] = one[i];
}
else
{
smallest[i] = two[i];
}
}

Getting top values from a list in c sharp

So I'm having some trouble with a C# program that is meant to sum the 8 highness value from a list.
The program works by declaring a variable currenthigh, which stores a value from the gradelist. It then compares itself to the value abshigh to see if it is greater than the established highest value. If it is, it sets currenthigh as the new highest value.
Once the loop has run through the list and confirmed the highest value, it adds it to the uppertotal variable and uses the ejector variable to remove it from the list. The program then iterates, this time without the previous highest value. It iterates 8 times so that in the end the top 8 values are added to uppertotal.
Trouble is, the highest variable remains in the list, despite the code having instructions to delete it, so it just adds the highest value to itself 8 times.
int currenthigh = 0;
int abshigh = 0;
int ejector = 0;
int uppertotal = 0;
for (int g = 0; g < 8; g++)
{
for (int z = 0; z < gradelist.Count; z++)
{
Console.WriteLine("PASS STARTED");
currenthigh = Convert.ToInt32((gradelist[z]));
Console.WriteLine("currenthigh" + currenthigh);
if (currenthigh > abshigh)
{
abshigh = currenthigh;
ejector = z;
}
}
Console.WriteLine("ejector" + ejector);
uppertotal = uppertotal + currenthigh;
gradelist.RemoveAt(ejector);
Console.WriteLine("PASS COMPLETE");
Console.WriteLine("RESETING");
}
Note - gradelist is a list of integers containing at least 12 items at all time.
This happens because you do not remove the highest value from gradelist. Pay attention, you put Z in ejector, but Z is an index in gradelist and when you try to remove it, you remove nothing because there is no Z in gradelist as a member! Instead of
gradelist.RemoveAt(ejector);
you should do this:
gradelist.RemoveAt(gradelist[ejector]);
But I'd recommend you completely different approach. If you just want to get your uppertotal which is the sum of top 8 members in gradlist, use this simple trick:
uppertotal += gradelist.OrderByDescending(p => p).Take(8).Sum();
Your code is extremely big for the relatively simple task.
You can select the top X of a list as follows:
top_list = gradelist.OrderByDescending(i => i).Take(X)
When working with lists/collections System.Linq is your friend

variable declared before cycle do not exist in cycle in c#

I am using c# and I have the flowing problem:
I decelerated the height variable before for cycle ant it says do not exist in the cycle.
In this part of the code I want the program to store all of the 3rd element of the "data" array except the first, so if the "data" array looks like this: 1,2,3,4,5,6,7,8,9,10,11,12... I want to get: 6,9,12...
static int[] tall()
{
int[] data = database();//recalling an array filled with numbers
int j = 0;
int[] height;
for (int i = 6; i < data.Length; )
{
i = i + 3;
j++;
height[j] = data[i];//Use of unassigned local variable 'height'
}
return height;
}
The compiler tells you what the problem is. Unfortunately, it does not tell you how to fix it.
You need to assign height to an array of int, but first you need to figure out its length. You can compute the length by subtracting the index of the initial data point (i.e. 6) from the length, dividing the result by 3, and adding 1. This can be simplified to (length-3)/3:
int[] height = new int[(data.Length-3)/3];
This assumes that data.Length is at least 4, otherwise the count is going to be negative.
You should also move the adjustment of indexes to a point after the assignment, or better yet, to the header of the loop:
// Start i at 5, because array indexes are zero-based.
for (int i = 5; i < data.Length; i+=3, j++) {
height[j] = data[i];
}
Demo.

Trying to make a 2D array of lists

I'm trying to write a model containing digital organisms. Within the model i'd liek the environment to be a fixed 2-d array, but each cell needs to contain a list of the organisms in it. I tried using a jagged array, but as the number of occupied elements varies quite a bit throughout the programm run, i need to use something more flexible than an array. I've tried making a 2-D array of the type list, but im getting errors with it.
List<Creature>[,] theWorld;
public Environment()
{
List<Creature>[,] theWorld = new List<Creature>[100,100];
}
public void addCreature(Creature c)
{
for (int x = 0; x < 100; x++)
{
for (int y = 0; y < 100; y++)
{
theWorld[x, y].Add (c);
} } }
this is the segment where i'm trying to declare the array at the beginning, as a type that holds lists (of the organisms), and later i try to add a creature (c) to each of the lists in each element of the array.
when i run it i get the following error message-
"An unhandled exception of type 'System.NullReferenceException' occurred in HGT_sim_2.exe
Additional information: Object reference not set to an instance of an object."
and the line "World[x, y].Add (c);" is highlighted.
If anyone can tell me what i'm doing wrong, and even better, a way around the problem, it'd be amazing.
thank you ain advance!
All your array contains initially is a lot of nulls. You need to actually create the lists...
for(int x = 0 ; x < 100 ; x++)
for(int y = 0 ; y < 100 ; y++)
theWorld[x,y] = new List<Creature>();
Personally, though, I expect this will be a costly way to do things...
It depends in part on whether the data is "sparse" - i.e. are most of the cells usually taken? A simple (but possibly more efficient) approach, for example, would be to use something like multi-map; i.e.
Point pt = new Point(x,y);
theWorld.Add(pt, someCreature);
where theWorld could be something like EditableLookup<Point, Creature> (using EditableLookup<,> from "MiscUtil"). That way, you can still query it by co-ordinate, and have multiple creatures on a coordinate, but you don't have to allocate space for every cell. And because it functions as a dictionary it is still fast. Not as fast as a flat array, but it will scale to bigger (sparse) grids... of course, if the grid has creatures on every cell it could be more expensive! Hence the need to understand your data.
You need to initialize each member of your array, e.g.
for (int x = 0; x < 100; x++)
{
for (int y = 0; y < 100; y++)
{
theWorld[x, y] = new List<Creature>();
} }
Here's the fix:
List<Creature>[,] theWorld;
public Environment()
{
theWorld = new List<Creature>[100,100]; // Remove the type, you were creating a new list and throwing it away...
for(int x = 0 ; x < 100 ; x++)
for(int y = 0 ; y < 100 ; y++)
theWorld[x,y] = new List<Creature>();
}
public void addCreature(Creature c)
{
for (int x = 0; x < 100; x++)
{
for (int y = 0; y < 100; y++)
{
theWorld[x, y].Add (c);
} } }
When you do this:
List<Creature>[,] theWorld = new List<Creature>[100,100];
You're creating an array of List<Creature> references, but they are all empty (pointing to null, not a valid List). You need to initialize each individual element:
for (int x = 0; x < 100; x++) {
for (int y = 0; y < 100; y++) {
theWorld[i,j] = new List<Creature>();
}
}
Once you've done that, you'll be able to call .Add on the individual members.
You're doing it almost correct. Your variable is a 2D array of List<Creature>. Now, List<Creature> is a reference type, so the array is initialized to contain null's in all its members. Thus you get the NullReferenceException. The line
theWorld[x, y].Add (c);
is basically equivalent to
null.Add (c);
All you need to do is to initialize all the members to contain instances of List<Creature>. The best way to do this would be in the constructor. Just rewrite it like this:
public Environment()
{
theWorld = new List<Creature>[100,100];
for(int x = 0 ; x < 100 ; x++)
for(int y = 0 ; y < 100 ; y++)
theWorld[x,y] = new List<Creature>();
}
Now all the operations will work as expected.
Also note, that in your example you are creating a local variable with the same name as the class member. This way you don't initialize the class member at all - it stays null.
You have created the array object to hold your lists, but you haven't created the list itself. You will need to do the following in your constructor:
for (int x = 0; x < 100; x++)
for (int y = 0; y < 100; y++)
theWorld[x,y] = new List<Creature>();
Another problem: you were also defining theWorld as a local variable in your constructor, which means your theWorld field on Environment was never initialized, either.
However, 10,000 Lists may be overkill for what you really need. If your Environment really needs a Creature at every point, and some Creatures may move to other points (where there is more than one at a point, then it may make more sense to use a Dictionary<Point, IList<Creature>> as your model versus 10,000 lists.
public void Add(Creature c, Point at)
{
IList<Creature> list;
if (!theWorld.TryGetValue(at)) {
list = theWorld[at] = new List<Creature>();
}
list.Add(c);
}
You can then implement Move and Remove methods similarly. Also, note that you are adding the same Creature to every point, which (may) mean that there's one Creature at all points in your Environment. You will probably want to create a new Creature() for every point, if that's what you are actually modeling.

Categories