(There's not an actual function where I need this, but I was just wondering.)
Imagine this function where I pass a bool[,]. This bool[,] is named grid1 or grid2, depending on the situation.
I was wondering if I can do anything like the following:
void CheckGrid(bool[,] grid, int number)
{
for (int x = 0; x <= gridXmax - 1; x++)
{
for (int y = 0; y <= gridYmax - 1; y++)
{
if(grid + number[x,y]) //this will check against grid1 or grid2, depending on int number
//logic depends on whether it's grid1 or grid2
}
}
}
Guessing by the questions for other languages, it probably isn't possible. But you never know :)
It is well possible I'm missing something obvious here - I'm not really experienced.
You can create an array of grids, then use the number value to check that.
List<bool[,] grids = new List<bool[,]>();
then
if (grids[number][x,y])...
No - an object doesn't have a name, only a variable has a name. So although you pass a reference to an array, there's no way that the method can know whether you happened to use a variable called grid1 for the argument or a variable called grid2.
Usually when there are questions like this, the answer involves saying that you can use reflection to access member variables by name, but it's generally a bad idea to do so - and that using a single variable which is a collection is a better idea. However, in your question it's pretty unclear what you're trying to do anyway... if it is trying to determine "the name of the object" then that's definitely infeasible in general.
You'd be better off passing a flag to your function which would allow you to update your logic depending on whether you are dealing with grid1 or grid2.
This kind of thing exists in PHP when you use something like this $$var where $var will hold grid1 and turn into $grid1
The only thing I could suggest was using key / value pairs in a dictionary and concatenating the number to 'grid'
Add a dimension to your array.
void CheckGrid(bool[,,] grid, int number)
{
for (int x = 0; x <= gridXmax - 1; x++)
{
for (int y = 0; y <= gridYmax - 1; y++)
{
if(grid[number, x,y]) //this will check against grid1 or grid2, depending on int number
//logic depends on whether it's grid1 or grid2
}
}
}
Related
Please help I have tried to move data from one datagridview column into an array in order to add (calculate) something from it and place it in another column called age. This is what I tried and wanted to see if the data is stored in an array but got a "use of unassigned local variable" error
string data;
int j = 3;
for (int i = 0; i < 10; i++)
{
data = Convert.ToString(dgvData[j, i].Value);
}
MessageBox.Show(data);
The variable data may not have a value assigned to it in the for loop, which would cause the MessageBox to fail. This can be resolved by instantiating data with a default value.
string data = "";
It looks like to me that you are also trying to display each value in the fourth column in the datagridview with MessageBox, so consider moving the MessageBox into the for loop. This could also allow you to move your data variable closer to the call, removing the need for the default value.
int j = 3;
for (int i = 0; i < 10; i++)
{
string data = Convert.ToString(dataGridView1[j, i].Value);
MessageBox.Show(data);
}
I'm using visual studio 2017, C#, Windows Forms to create an index for words in a list of sentences.
I have two datagridview:
dataGridView2: This grid has a single column where each row contains a worded sentence.
dGvTopics: This grid has one column for every word that is repeated in the first sentence (first row) in dataGridView2, the column header text is the word.
Goal: I want to click button to categorize, inserting a row in dGvTopics for each row in dataGridView2 (sentences), place a copy of the sentence as the value for that column if the sentence contains the column header text.
My Code is:
private void btnClassify_Click(object sender, EventArgs e)
{
for (int i = 0; i < dGvTopics.Columns.Count; i++)
{
if (dataGridView2.Rows[i].Cells[0].Value.ToString().Contains(dGvTopics.Columns[i].HeaderText))
{
this.dGvTopics.Rows.Add();
this.dGvTopics.Rows[i].Cells[i].Value = dataGridView2.Rows[i].Cells[0].Value;
}
}
}
We can discuss later why you are doing this at all, there are easier ways :)
You need to understand that there are two dimensions to iterate here, the rows in dataGridView2 and the columns in dGvTopics, this means you will need two looping statements, not just one.
Your current code is looping through the Rows in dataGridView2 but only for the number of columns that are in dGvTopics which is a bit confusing.
PRO TIP: Don't use arbitrary single character variable names that have no meaning. Yes i is ubiquitously used to represent index in code you will find around the web, that doesn't mean it is good practice. i should be reserved for lazy programming where there is a single, single dimension array that you are iterating over, in your example there are 4 different levels of arrays that you accessing, the meaning of i is now ambiguous.
Instead of i, use a meaningful variable name like columnIndex or topicIndex. That way when each line is reviewed in isolation, the code is more self documenting. I would even accept t or c in this code, taking the first initial from the conceptual variable meaning will help spot common errors where the wrong indexer is used for the wrong array.
Yes this make the code wordy and long, but we're not constrained by memory space in the same way as our developer ancestors, this doesn't change the size of the final executable, strive to make your code self-documenting.
If you are programming in a code-memory-constrained environment, like for micro-controllers, or tiny chipsets, then still use meaningful short variables, not arbitrarily selected characters.
Applying the above recommendation highlights this first issue:
for (int columnIndex = 0; columnIndex < dGvTopics.Columns.Count; columnIndex ++)
{
if (dataGridView2.Rows[columnIndex].Cells[0].Value.ToString().Contains(dGvTopics.Columns[columnIndex].HeaderText))
{
this.dGvTopics.Rows.Add();
this.dGvTopics.Rows[columnIndex].Cells[columnIndex].Value = dataGridView2.Rows[columnIndex].Cells[0].Value;
}
}
Now we can see that each iteration is moving down the rows, but across the cells at the same rate, meaning that only the cells in a diagonal formation will even be compared and have a value.
The next issue is that because you are only creating a row when the comparison returns true, this means that the rows in dGvTopics might be less than you are expecting, which means less than the value of i (or columnIndex) which will raise an IndexOutOfRangeException the next successful iteration after any comparison that fails.
You can avoid this problem by iterating over the rows and columns separately and adding one row in dGvTopics for every row in dataGridView2.
We can also make the code clearer by saving a reference to the currentSentence rather than referencing the sentence through the array indexers.
private void btnClassify_Click(object sender, EventArgs e)
{
// remove any existing rows, we will reprocess all records.
this.dGvTopics.Rows.Clear();
// Iterate over the rows in the list of sentences.
for (int rowIndex = 0; rowIndex < dataGridView2.Rows.Count; rowIndex ++)
{
// Create one topic row for every sentence
// row index will always be valid now.
this.dGvTopics.Rows.Add();
// save the sentence value to simplify the comparison code.
string currentSentence = dataGridView2.Rows[rowIndex].Cells[0].Value.ToString();
// iterate over the columns in the topics grid
for (int columnIndex = 0; columnIndex < dGvTopics.Columns.Count; columnIndex ++)
{
if (currentSentence.Contains(dGvTopics.Columns[columnIndex].HeaderText))
{
this.dGvTopics.Rows[rowIndex].Cells[columnIndex].Value = currentSentence;
}
}
}
}
It's not easy to comprehend why you want to do this or how this information will be used. In general for manipulating values in cells we generally recommend that databinding techniques are used instead, that way you do not access rows and cells anymore or but the underlying objects that they represent.
demonstrating this is outside of the scope of this question, but it's an avenue worth researching when you have time.
In solutions like this where there are two grids that represent the same logical component, (in this case each row in each grid represents the same sentence value) the underlying dataobject might be a single list, where one property on the object is the sentence and each topic column is a property on the same object.
Importantly, using databinding means that the next process that needs to use the information that you have displayed or edited in the grids can do so without access to or knowledge about the grids at all... Something to think about ;)
Update
This code may result in many empty cells in the topics grid. We could instead only add rows as they are needed, but to do this will require a lot more effort.
NOTE: Grids render all the cells for each row, In the last couple of rows, there may still be empty cells if at least one of the cells for that row has a value.
private void btnClassify_Click(object sender, EventArgs e)
{
// remove any existing rows, we will reprocess all records.
this.dGvTopics.Rows.Clear();
// Iterate over the rows in the list of sentences.
for (int rowIndex = 0; rowIndex < dataGridView2.Rows.Count; rowIndex ++)
{
// save the sentence value to simplify the comparison code.
string currentSentence = dataGridView2.Rows[rowIndex].Cells[0].Value.ToString();
// iterate over the columns in the topics grid
for (int columnIndex = 0; columnIndex < dGvTopics.Columns.Count; columnIndex ++)
{
if (currentSentence.Contains(dGvTopics.Columns[columnIndex].HeaderText))
{
// first we need to know what row index to add this value into
// that involves another iteration, we could store last index in another structure to make this quicker, but here we will do it from first principals.
bool inserted = false;
for(int lookupRow = 0; lookupRow < this.dGvTopics.Rows.Count; lookupRow ++)
{
// find the first row with a null cell;
if(this.dGvTopics.Rows[columnIndex].Value == null)
{
this.dGvTopics.Rows[lookupRow].Cells[columnIndex].Value = currentSentence;
inserted = true;
break;
}
}
if(!inserted)
{
this.dGvTopics.Rows.Add();
this.dGvTopics.Rows[this.dGvTopics.Rows.Count-1].Cells[columnIndex].Value = currentSentence;
}
}
}
}
}
Many thanks to Mr Chris Schaller,
According to his description, the final code changed as follows after compiling:
private void btnClassify_Click(object sender, EventArgs e)
{
// remove any existing rows, we will reprocess all records.
this.dGvTopics.Rows.Clear();
// Iterate over the rows in the list of sentences.
for (int rowIndex = 0; rowIndex < dataGridView2.Rows.Count; rowIndex++)
{
// save the sentence value to simplify the comparison code.
string currentSentence = dataGridView2.Rows[rowIndex].Cells[0].Value.ToString();
// iterate over the columns in the topics grid
for (int columnIndex = 0; columnIndex < dGvTopics.Columns.Count; columnIndex++)
{
if (currentSentence.Contains(dGvTopics.Columns[columnIndex].HeaderText))
{
// first we need to know what row index to add this value into
// that involves another iteration, we could store last index in another structure to make this quicker, but here we will do it from first principals.
bool inserted = false;
for (int lookupRow = 0; lookupRow < this.dGvTopics.Rows.Count; lookupRow++)
{
// find the first row with a null cell;
if (this.dGvTopics.Rows[lookupRow].Cells[columnIndex].Value == null)
{
this.dGvTopics.Rows[lookupRow].Cells[columnIndex].Value = currentSentence;
inserted = true;
break;
}
}
if (!inserted)
{
this.dGvTopics.Rows.Add();
this.dGvTopics.Rows[this.dGvTopics.Rows.Count - 1].Cells[columnIndex].Value = currentSentence;
}
}
}
}
}
I have a contract that does this:
for (int i = 0; i < delegateParameterTypes.Length; i++)
{
Contract.Assert(i < delegateParameterTypes.Length);
Contract.Assert(delegateParameterTypes.Length == methodParameters.Length + (1));
// Q.E.D.
Contract.Assert(i < methodParameters.Length + (1));
}
The first two pass analysis fine but the third says that the assert is unproven, off by one? consider guard.
It seems like simple math. is there something I'm missing?
trying it with string arrays and local values seems to work fine. Might be to do with the .Length call somehow? I tried swapping the int to UInt16 to see if it's due to buffer overflow in a loop but that wasn't it either.
Hmm, the only thing I can think of is that the static analyzer is having a problem with these asserts. Follow me on this:
You call Contract.Assert(i < delegateParameterTypes.Length);. Assuming this is true, we go on.
At this point, the static analyzer doesn't know if anything has changed about delegateParameterTypes.Length between the call that's about to happen to Contract.Assert(predicate) and step 1 above. You and I know nothing happened, but the analyzer does not--despite the fact the two lines of code are adjacent (who's to say there's not some thread touching shared state out there somewhere?)
You make the next call: Contract.Assert(delegateParameterTypes.Length == methodParameters.Length + (1)); The analyzer checks this, and this is OK, too.
At this point, the analyzer has no idea whether anything's changed about delegateParameterTypes or methodParameters--QED, Assert unproven for Contract.Assert(i < methodParameters.Length + (1)); on the next line.
Again, there could be some shared global state associated with those things, and that state could have changed between the two calls to Contract.Assert. Remember, to you and me, the code looks linear and synchronous. The reality is or could be quite different, and the static analyzer can make no assumptions about the state of those objects between successive calls to Contract.Assert.
What may work, however:
int delegateParameterTypesLength = delegateParameterTypes.Length;
int methodParametersLength = methodParameters.Length + 1;
for (int i = 0; i < delegateParameterTypesLength; i++)
{
Contract.Assert(delegateParameterTypesLength == methodParametersLength);
// QED
Contract.Assert(i < methodParametersLength);
}
By assigning the lengths to variables, the static analyzer can now know that those values don't change within the for loop, or external of the method in which they're assigned. Now you're comparing i with values that are known not to change. Now, the static analyzer can make some inferences about the comparisons of these values and should be able to prove the assertions.
I got an arraylist of rectangles and I want to edit the X & Y values of all of them.
I tried using a foreach loop
foreach (Rectangle rect in rectangles)
rect.X += 1;
But this wouldn't work as it's read-only, so I tried a regular for loop
for (int i = 0; i < rectangles.Count; i++)
rectangles[i].X += 1;
And for some reason this wouldn't work either, because rectangles[i] just doesn't have any of rectangle's methods.
Then I stumbled across a post somewhere on stackoverflow about how to call methods of elements of an arraylist. And I haven't been able to find examples of this, so I hope someone can clear this up.
(Unit.unitArray[selectedUnit] as MyClass).DisplayUnitAttributes()
But I have no idea how to put this to use, I don't understand what Unit is supposed to be replaced with, and I'm guessing MyClass would be Rectangle...
Any help is appreciated!
TLDR: I want to iterate over an arraylist with rectangles, and edit the X & Y values of them.
According to the error you have got. "Return value is not a variable"
Rectangle is not a class. its an struct which is not reference type so you have to assign new value into it.
List<Rectangle> rectangles = new List<Rectangle>();
// rectangles.Add(x); make your list here
for (int index = 0; index < rectangles.Count; index++)
{
Rectangle r = rectangles[index];
r.x += 1;
rectangles[index] = r;
}
It's act like this because ArrayList is not typed. It's better to use a List<T> instead (where T is your class, in your example it will be a Rectangle). Here is MSDN link.
You can't modify object this way in the foreach loop. More info on this SO question.
About this example: (Unit.unitArray[selectedUnit] as MyClass).DisplayUnitAttributes()
It's called casting. You can read more about this on this SO question. So in your code it should looks like this: (rectangles[i] as Rectangle).X += 1;. You also should check if result of this casting is not null etc. But better read previous link to understand this.
This is my idea to program a simple math module (function) that can be called from another main program. It calculates the FWHM(full width at half the max) of a curve. Since this is my first try at Visual Studio and C#. I would like to know few basic programming structures I should learn in C# coming from a Mathematica background.
Is double fwhm(double[] data, int c) indicate the input arguments
to this function fwhm should be a double data array and an Integer
value? Did I get this right?
I find it difficult to express complex mathematical equations (line 32/33) to express them in parenthesis and divide one by another, whats the right method to do that?
How can I perform Mathematical functions on elements of an Array like division and store the results in the same Array?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DEV_2
{
class fwhm
{
static double fwhm(double[] data, int c) // data as 2d data and c is integer
{
double[] datax;
double[] datay;
int L;
int Mag = 4;
double PP = 2.2;
int CI;
int k;
double Interp;
double Tlead;
double Ttrail;
double fwhm;
L = datay.Length;
// Create datax as index for the number of elemts in data from 1-Length(data).
for (int i = 1; i <= data.Length; i++)
{
datax[i] = (i + 1);
}
//Find max in datay and divide all elements by maxValue.
var m = datay.Length; // Find length of datay
Array.ForEach(datay, (x) => {datay[m++] = x / datay.Max();}); // Divide all elements of datay by max(datay)
double maxValue = datay.Max();
CI = datay.ToList().IndexOf(maxValue); // Push that index to CI
// Start to search lead
int k = 2;
while (Math.Sign(datay[k]) == Math.Sign(datay[k-1]-0.5))
{
k=k+1;
}
Interp = (0.5-datay[k-1])/(datay[k]-datay[k-1]);
Tlead = datax[k-1]+Interp*(datax[k]-datax[k-1]);
CI = CI+1;
// Start search for the trail
while (Math.Sign(datay[k]-0.5) == Math.Sign(datay[k-1]-0.5) && (k<=L-1))
{
k=k+1;
}
if (k != L)
{
Interp = (0.5-datay[k-1])/(datay[k]-datay[k-1]);
Ttrail = datax[k-1] + Interp*(datax[k]-datax[k-1]);
fwhm =((Ttrail-Tlead)*PP)/Mag;
}
}//end main
}//end class
}//end namespace
There are plenty of pitfalls in C#, but working through problems is a great way to find and learn them!
Yes, when passing parameters to a method the correct syntax is MethodName(varType varName) seperated by a comma for multiple parameters. Some pitfalls arise here with differences in passing Value types and Reference types. If you're interested here is some reading on the subject.
Edit: As pointed out in the comments you should write code as best as possible to require as few comments as possible (thus paragraph between #3 and #4), however if you need to do very specific and slightly complex math then you should comment to clarify what is occuring.
If you mean difficulties understanding, make sure you comment your code properly. If you mean difficulties writing it, you can create variables to simplify reading your code (but generally unnecessary) or look up functions or libraries to help you, this is a bit open ended question if you have a particular functionality you are looking for perhaps we could be of more help.
You can access your array via indexes such as array[i] will get the ith index. Following this you can manipulate the data that said index is pointing to in any way you wish, array[i] = (array[i]/24)^3 or array[i] = doMath(array[i])
A couple things you can do if you like to clean a little, but they are preference based, is not declare int CI; int k; in your code before you initialize them with int k = 2;, there is no need (although you can if it helps you). The other thing is to correctly name your variables, common practice is a more descriptive camelCase naming, so perhaps instead of int CI = datay.ToList().IndexOf(maxValue); you coud use int indexMaxValueYData = datay.ToList().IndexOf(maxValue);
As per your comment question "What would this method return?" The method will return a double, as declared above. returnType methodName(parameters) However you need to add that in your code, as of now I see no return line. Such as return doubleVar; where doubleVar is a variable of type double.