public partial class Form1 : Form
{
string[] id;
private void button_Click(object sender, EventArgs e)
{
char[] delimiters = { ',', '\r', '\n' };
string[] content = File.ReadAllText(CSV_File).Split(delimiters);
int x = content.GetUpperBounds(0)
int z = 0;
int i - 0;
for (i = 0; i <= x / 3; i++)
{
z = (i * 3);
id[i] = content[z]; // this line gives the error
}
}
}
I want to get every 3rd value from array content, and put it into array id. This gives a 'NullReferenceException was unhandled' error and suggests I use 'new', but it is not a type or namespace. What should I do here?
They are both string arrays, and the error occurs on the first run so I do not think it is related to exceeding the bounds.
You need to initialize id array before the for loop:
id = new string[x/3];
This line of code:
string[] id;
is actually creating a null reference.
When you declare an array, you have to explicitly create it, specifying the size.
In your example, you have two alternatives
Determine how big the array will be beforehand, and create the array length
Actually populate a container that manages its own size.
The first option:
int x = content.GetUpperBounds(0)
int z = 0;
int i - 0;
id = new string[x/3];
for (i = 0; i <= x / 3; i++)
{
z = (i * 3);
id[i] = content[x];
}
The second option:
int x = content.GetUpperBounds(0)
int z = 0;
int i - 0;
List<string> list = new List<string>();
for (i = 0; i <= x / 3; i++)
{
z = (i * 3);
list.Add(content[z]);
}
id = list.ToArray();
The first option would perform better, as you are only allocating one object.
Admittedly, I tend to disregard performance and use the second option, because it takes less brainpower to code.
Related
i trying to shuffle the numbers currently contained within a listbox.
However getting an error with my index
I am able to do this with an array, although now I am trying to shuffle without the use of any containers or arrays, but having problems doing so.
this.index = 0;
int a = Convert.ToInt32(lstHoldValue.Items.Count);
lstHoldValue.Items.Clear();
for (int i = 0; i < a; i++)
{
int idx = rnd.Next(i, a);
//swap elements
int tmp = Convert.ToInt32(lstHoldValue.Items[i]);
(lstHoldValue.Items[i]) = Convert.ToInt32(lstHoldValue.Items[idx]);
(lstHoldValue.Items[idx]) = Convert.ToInt32(tmp);
lstHoldValue.Items.Add("\t" + Convert.ToInt32(lstHoldValue.Items[i]));//show array in a listbox
}
this.index = 0;//what is this for?
int a = listHoldValue.Count;//Count returns an integer by default
// lstHoldValue.Items.Clear(); //remove this line,it clears the items stored
for (int i = 0; i < a; i++)
{
int idx = rnd.Next(i, a);
//swap elements
int tmp = Convert.ToInt32(lstHoldValue.Items[i]);
lstHoldVAlue.Items.Insert(i,lstHoldValue.Items[idx]);
(lstHoldValue.Items[i]) = Convert.ToInt32(lstHoldValue.Items[idx]);
(lstHoldValue.Items.Insert(idx,temp);
lstHoldValue.Items.Add("\t" + Convert.ToInt32(lstHoldValue.Items[i]));//this line is redundant because you have already added item[i] at index [idx]
}
I am creating a calculator where the user enters a number into a textbox specifing how many inputs (textboxes) the user wants to have (Code not shown). I have used a textbox array to create these textboxes. The problem comes when I want to get the text from these textboxes to perform the calculations, the code I have written so far for this is shown below:
int n;
TextBox[] textBoxes;
Label[] labels;
double[] values;
public void GetValue()
{
n = Convert.ToInt16(txtInputFields.Text);
values = new double[n];
textBoxes = new TextBox[n];
for (int i = 0; i < n; i++)
{
}
}
I am unsure what to put in the for loop for this; I have tried the following:
values[n] = Convert.toDouble(textBoxes[n].Text);
but it gives me the error: Index was outside the bounds of the array.
I am new to C# and programming in general so any help would be much appreciated.
Thanks.
EDIT: Code to create textboxes is shown here:
public void InstantiateTextFields()
{
n = Convert.ToInt16(txtInputFields.Text);
int posLeft = 100;
textBoxes = new TextBox[n];
labels = new Label[n];
// Creates number of inputs and labels as specified in txtInputFields (n).
for (int i = 0; i < n; i++)
{
textBoxes[i] = new TextBox();
textBoxes[i].Top = 100 + (i * 30);
textBoxes[i].Left = posLeft;
textBoxes[i].Name = "txtInput" + (i + 1);
labels[i] = new Label();
labels[i].Top = 100 + (i * 30);
labels[i].Left = posLeft - 50;
labels[i].Text = "Input " + (i + 1);
labels[i].Name = "lblInput" + (i + 1);
}
for (int i = 0; i < n; i++)
{
this.Controls.Add(textBoxes[i]);
this.Controls.Add(labels[i]);
}
}
Your code in the GetValue method recreates the array of textboxes and doing so destroys the orginal content (the textboxes dynamically created InstantiateTextFields).
In this way your loop fails with Object Reference not set.
You just need to use the global variable without reinitiaizing it
public void GetValue()
{
n = Convert.ToInt16(txtInputFields.Text);
values = new double[n];
// textBoxes = new TextBox[n];
for (int i = 0; i < n; i++)
{
values[i] = Convert.ToDouble(textBoxes[i].Text);
}
}
There is something to be said about reading the input text and converting it to double without checks. If your user types something that cannot be converted to a double your code will crash on the Convert.ToDouble line. Use instead
double temp;
for (int i = 0; i < n; i++)
{
if(double.TryParse(textBoxes[i].Text, out temp)
values[i] = temp;
else
{
// Not a double value....
// A message to your user ?
// fill the array with 0 ?
// Your choice....
}
}
values[n] = Convert.toDouble(textBoxes[n].Text); gives you error because n is outside of the array. You allocate an array with the size of n which is zero indexed aka the last element is at position n-1.
for (int i = 0; i < n; i++)
{
values[i] = Convert.toDouble(textBoxes[i].Text);
}
In a great many places in the software I write, there are three-dimensioned arrays of short or float, usually with several million elements. The data is best understood conceptually as a three-dimensioned array, since it describes values at regular locations in space.
I saw a mention elsewhere here that the .NET CLR is not terribly "performant" when it comes to traversing those arrays, for example, when computing new values and populating a second, equally sized and dimensioned array. If this is true, why is that so?
For reasons of readability I've not settled on the idea of using jagged arrays, yet, but if that's really the answer then I'm willing, but:
To get around this it's been proposed to me that I format the data as a single dimensioned array. For example, if my array has dimensions with magnitudes m, n, and o, then I would create a float[m*n*o] instead of a float[m,n,o], and write my own indexer to get to the correct array locations during traversal.
The specific use case is in parallelizing the traversal, such as:
Parallel.For(0,m)((x) => for(y=0,y<n,y++) { for(z=0,z<o,z++) doSomething(array(x,y,z)); });
Where in the single-indexed case there would be a Parallel.ForEach(myArray, (position) => doSomething(array(Position))) kind of thing going on instead of the nested for loops.
So, the question is, really, would that be any faster than relying on the CLR array indexing that's built in?
EDIT: I've supplied my own answer below, based on some timing tests. The code is included.
One huge thing to consider is the order of traversal. Memory caching is an important part of modern processor performance and cache misses can be (relatively) expensive. If you index the array across a 'long' dimension that results in crossing cache boundaries, you may cause frequent misses as part of indexing. As such, the order in which you index is important. This often means you want to take care in how you choose to order your indices.
Also, when copying, consider that multiple indexing requires computing the 'true' index to the underlying memory block using multiplication/addition. If you're just copying all elements, though, you could simply increment a single index and access each element without additional computation required.
There are also various condition checks that occur when accessing arrays by index (making the IndexOutOfRangeException possible), which requires more checks when you access via multiple indices. I believe (though I'm not entirely sure) that the jitter can sometimes optimize single dimensional array access using a simple loop by checking the range only once, rather than on every indexing operation.
I ran some timings and found that overall performance is that it makes little or no difference:
I used this code below. The timings I got were basically identical in each case:
public partial class Form1 : Form
{
int ArrayDim1 = 50;
int ArrayDim23 = 500;
int ParallelSplit = 50;
int DoSomethingSize = 100;
Double sqRoot = 0;
Single[, ,] multidim = null;
Single[] singleDim = null;
Single[][][] jagged = null;
ParallelOptions po = new ParallelOptions() { MaxDegreeOfParallelism = 36 };
public Form1()
{
InitializeComponent();
multidim = new Single[ArrayDim1, ArrayDim23, ArrayDim23];
for (int x = 0; x < ArrayDim1; x++)
for (int y = 0; y < ArrayDim23; y++)
for (int z = 0; z < ArrayDim23; z++)
multidim[x, y, z] = 1;
singleDim = new Single[ArrayDim1 * ArrayDim23 * ArrayDim23];
for (int i = 0; i < singleDim.Length; i++)
singleDim[i] = 1;
jagged = new Single[ArrayDim1][][];
for (int i = 0; i < ArrayDim1; i++)
{
jagged[i] = new Single[ArrayDim23][];
for (int j = 0; j < ArrayDim23; j++)
{
jagged[i][j] = new Single[ArrayDim23];
}
}
}
private void btnGO_Click(object sender, EventArgs e)
{
int loopcount = 1;
DateTime startTime = DateTime.Now;
for (int i = 0; i < loopcount; i++)
{
TestMultiDimArray(multidim);
}
textBox1.Text = DateTime.Now.Subtract(startTime).TotalMilliseconds.ToString("#,###");
startTime = DateTime.Now;
for (int i = 0; i < loopcount; i++)
{
TestSingleArrayClean(singleDim);
}
textBox2.Text = DateTime.Now.Subtract(startTime).TotalMilliseconds.ToString("#,###");
startTime = DateTime.Now;
for (int i = 0; i < loopcount; i++)
{
TestJaggedArray(jagged);
}
textBox3.Text = DateTime.Now.Subtract(startTime).TotalMilliseconds.ToString("#,###");
}
public void TestJaggedArray(Single[][][] multi)
{
Parallel.For(0, ArrayDim1, po, x =>
{
for (int y = 0; y < ArrayDim23; y++)
{
for (int z = 0; z < ArrayDim23; z++)
{
DoComplex();
multi[x][y][z] = Convert.ToSingle(Math.Sqrt(123412341));
}
}
});
}
public void TestMultiDimArray(Single[, ,] multi)
{
Parallel.For(0, ArrayDim1, po, x =>
{
for (int y = 0; y < ArrayDim23; y++)
{
for (int z = 0; z < ArrayDim23; z++)
{
DoComplex();
multi[x, y, z] = Convert.ToSingle(Math.Sqrt(123412341));
}
}
});
}
public void TestSingleArrayClean(Single[] single)
{
Parallel.For(0, single.Length, po, y =>
{
//System.Diagnostics.Debug.Print(y.ToString());
DoComplex();
single[y] = Convert.ToSingle(Math.Sqrt(123412341));
});
}
public void DoComplex()
{
for (int i = 0; i < DoSomethingSize; i++)
{
sqRoot = Math.Log(101.101);
}
}
}
I'm getting "reference to an object was not set for an instance of the object" run-time error with the suggestion: "Use the new keyword to create an object instance.
But I don't understand what I'm doing wrong.
There is my code:
int numListas = 10;
x = 15;
int[][] listas;
listas = new int[numListas][];
Random random = new Random(); // generate random number
for (idx = 0; idx < numListas; idx++)
{
int idx_el;
for (idx_el = 0; idx_el < x ; idx_el++)
{
listas[idx][idx_el] = random.Next(0,100);
}
}
This line:
int[][] listas;
declares a variable which is a reference to an array of arrays.
This line:
listas = new int[numListas][];
initializes the variable to refer to an array of numListas array references... but each of those "subarray" references is null to start with. You need to initialize each "subarray", probably in your outer loop:
for (idx = 0; idx < numListas; idx++)
{
listas[idx] = new int[x];
...
}
Note that an alternative is to use a rectangular array instead of an array of arrays:
int[,] listas = new int[numListas, x];
...
// In your loop
listas[idx, idx_el] = random.Next(0, 100);
As an aside, code generally reads more clearly when you declare and initialize variables together, rather than declaring them earlier and then initializing them later. Also, underscores in C# variable names aren't terribly idiomatic, and the overall variable names aren't terribly clear. I'd write your code as:
// Consider declaring these as constants outside the method
int rowCount = 10;
int columnCount = 15;
int[][] values = new int[rowCount];
Random random = new Random();
for (int row = 0; row < rowCount; row++)
{
values[row] = new int[columnCount];
for (int column = 0; column < columnCount; column++)
{
values[row][column] = random.Next(100);
}
}
You should also consider initializing a single Random instance outside the method and passing it in - see my article on Random for more information.
You need to initialize each inner array within your jagged array:
int numListas = 10;
x = 15;
int[][] listas;
listas = new int[numListas][];
Random random = new Random(); // generate random number
for (idx = 0; idx < numListas; idx++)
{
listas[idx] = new int[x]; // initialize inner array
int idx_el;
for (idx_el = 0; idx_el < x ; idx_el++)
{
listas[idx][idx_el] = random.Next(0,100);
}
}
Alternatively, you may use a two-dimensional array:
int numListas = 10;
x = 15;
int[,] listas;
listas = new int[numListas,x]; // 2D array
Random random = new Random(); // generate random number
for (idx = 0; idx < numListas; idx++)
{
int idx_el;
for (idx_el = 0; idx_el < x ; idx_el++)
{
listas[idx,idx_el] = random.Next(0,100);
}
}
You don't set a dimension for the second dimension
listas = new int[numListas][];.
As you are using x as the limit of your loop, use that as dimension:
for (idx = 0; idx < numListas; idx++)
{
int idx_el;
listas[idx] = new int[x]; // initialize the second dimension
for (idx_el = 0; idx_el < x ; idx_el++)
{
listas[idx][idx_el] = random.Next(0,100);
}
}
Alternatively, you can use a rectangular array at the beginning:
int[,] listas = new int[numListas,x];
Did you forget to initialize the second dimension of the array?
listas = new int[numListas][x];
initialize this ^
I have a 2-dimensional array of objects, which I initialize using the traditional loop:
PairDS[,] tempPb1 = new PairDS[LoopCounterMaxValue+1, LoopCounterMaxValue+1];
for (int i = 0; i <= LoopCounterMaxValue; i++)
for (int j = 0; j <= LoopCounterMaxValue; j++)
tempPb1[i, j] = new PairDS();
Is there any better way to do this using Enumerable or something?
I thought Initialize could do it, but it only works with value types.
int N = 10;
PairDS[,] temp = new PairDS[N + 1, N + 1];
temp.Initialize();
What I recommend you do is use a jagged array.
class PairDS { public PairDS(int row, int col) { } }
static void Main(string[] args)
{
int N = 10;
PairDS[][] temp = Enumerable.Range(0, N + 1).Select(
(row) => Enumerable.Range(0, N + 1).Select(
(col) => new PairDS(row, col)).ToArray()).ToArray();
}
I don't believe you can represent a multi-dimensional array as an Enumerable or List, directly because it (the CLR) has no way of knowing how you intend to index the array.
If you did work it out row by row, it'd actually be worse (ie slower) then simply looping through the array as you're doing and initializing each cell.
There's no way to directly initialize a 2D array with the Enumerable types and as some users have pointed out there's nothing directly wrong with what you're doing. If you're just looking to simplify the loop though this might be what you're looking for;
const int length = LoopCounterMaxValue + 1;
PairDS[,] tempPb1 = new PairDS[length, lenth];
for (var i = 0; i < length * length; i++) {
var column = i % length;
var row = (i - column) / length;
tempPb1[row, column] = new PairDS();
}