I have a program that generates a grid of buttons and i want to store these buttons in an nested array list but the way I am doing does not seem to be correct
This is my code:
List<List<Button>> buttonsList = new List<List<Button>>();
List<Button[]> rowList = new List<Button[]>();
//Some method that creates a grid of buttons
buttons = new Button[row][];
for (int r = 0; r < row; r++)
{
buttons[r] = new Button[col];
buttonsList.Add(rowList[r]);
for (int c = 0; c < col; c++)
{
buttons[r][c] = new Button();
rowList[c].Add(buttons[r][c]);
}
}
First thing you need to understand is that a List<T> and a T[] are not equivalent* (*see footnote). Your code seems to want to treat a list as an array, and that's just not going to work.
A List<List<Button>> can be used in the following manner:
var listOfLists = new List<List<Button>>();
var listOfButtons = new List<Button>();
listOfButtons.Add(new Button());
listOfLists.Add(listOfButtons);
And you can continue to add buttons to the button list, create more button lists, add buttons to those, and add all of them to the list of lists and you can do all of this in a loop or nested loops.
An array Button[][] is treated differently. It's not dynamically sized, and would be used in a different manner.
var arrayOfArrays = new Button[10][];
var arrayOfButtons = new Button[3];
arrayOfButtons[0] = new Button();
arrayOfButtons[1] = new Button();
arrayOfButtons[2] = new Button();
arrayOfArrays[0] = arrayOfButtons;
And then you still have 9 more arrays of buttons you could set (in this example).
Your code attempts to add an array of buttons to a list expecting a list of buttons. And there are a few other items to sort through, but the basic idea is that you are mixing up these two different collections, and the compiler is loudly complaining.
To fix your code, begin by employing the proper types for what you need to do, and then consistently and correctly use those types in your logic.
As a starter, see how far you get with these snippets.
// using List<List<Button>>
var buttonLists = new List<List<Button>>();
for (int r = 0; r < row; r++)
{
var buttonRow = new List<Button>();
buttonLists.Add(buttonRow);
for (int c = 0; c < col; c++)
{
buttonRow.Add(new Button());
}
}
// using Button[][]
var buttonArrays = new Button[row][];
for (int r = 0; r < row; r++)
{
buttonArrays[r] = new Button[col];
for (int c = 0; c < col; c++)
{
buttonArrays[r][c] = new Button();
}
}
*Unless you are referencing them via a common interface type, in which case they still aren't equivalent but are compatible, but that is beyond the scope of this answer and not particularly useful in this context, given the code snippets involved.
Related
Question: How to distribute items in number of lists? following are examples:
Imagine I have a 8 lists, and 5 items. in this case list 1 to 5 will have 1 item. rest of lists remain empty.
Now If I have 8 lists and 16 items each list will have 2 items.
If I have 8 lists and 11 items, list 1 to 3 will have two items. rest of the lists will have 1 item.
var items = new List<object>();
var containers = new List<List<object>>();
int c = -1; // indexer for container.
for(int i = 0; i < items.Count; i++)
{
// disturbute items to containers
if (i % (items.Count/containers.Count) == 0) c++; // this is wrong. when to increment?
containers[c].Add(items[i]);
}
I'm pretty sure only if statement is wrong. Its getting confusing how to handle i.
Try this:
static void Main(string[] args)
{
var items = new List<object>() {1, 2, 3, 4, 5, 6};
var containers = new List<List<object>>() { new List<object>(), new List<object>(), new List<object>()};
int c = 0; // indexer for container.
int containerCount = containers.Count;
for (int i = 0; i < items.Count; i++, c++)
{
c = c % containerCount;
containers[c].Add(items[i]);
}
}
Think about the algorithm. When inserting item, you insert it to a list and then move to next one. When reaching last list, start inserting back to the first. Code (written in notepad, so may not compile):
var items = new List<object>();
var containers = new List<List<object>>();
int c = 0;
for (int i = 0; i < items.Count; i++)
{
c++; // move to next container
// when reached to the end, insert again to first list
if (c == containers.Count)
{
c = 0;
}
containers[c].Add(items[i]);
}
This can be made a bit shorter:
var items = new List<object>();
var containers = new List<List<object>>();
int c = 0;
foreach (int item in items)
{
c = (c == containers.Count - 1) ? 0 : c + 1;
containers[c].Add(item);
}
If you want to isolate this behavior into something reusable and testable:
public class ListBalancer
{
public void BalanceItemsBetweenLists<T>(
IEnumerable<T> input,
IEnumerable<IList<T>> targets)
{
var inputArray = input as T[] ?? input.ToArray();
var targetArray = targets as IList<T>[] ?? targets.ToArray();
var currentTargetIndex = 0;
foreach (var item in inputArray)
{
targetArray[currentTargetIndex].Add(item);
currentTargetIndex++;
if (currentTargetIndex == targetArray.Length) currentTargetIndex = 0;
}
}
}
[TestClass]
public class ListBalancerTests
{
[TestMethod]
public void BalancesListsWhenAddingItems()
{
var source = Enumerable.Range(1, 11);
var targets = Enumerable.Range(1, 8).Select(n => new List<int>()).ToArray();
new ListBalancer().BalanceItemsBetweenLists(source, targets);
Assert.AreEqual(2, targets[0].Count);
Assert.AreEqual(2, targets[1].Count);
Assert.AreEqual(2, targets[2].Count);
Assert.AreEqual(1, targets[3].Count);
}
}
It seems like a little bit of extra work. But you probably found that the process of debugging when it didn't do what was expected took a little extra time, too. It might have been necessary to start a console application or some other app to test the behavior. If you write a class with a unit test you might still have to debug, but it's faster and more self-contained. You finish the one class with the one behavior, test it, and then move on.
Personally I found that once I formed the habit I could write code a little faster and with fewer bugs because I made my debugging process smaller and easier.
I've got myself into a little bit of a jam. As I tried to code the entire alphabet into my app, I didn't really feel like typing the letters in one by one, so I used ASCII characters and used a for-loop and inserted them as buttons. So, now I need those buttons to click according to my needs, but somehow I cant seem to figure out what is the problem with the issue. The code is as follows:
private void Hangman_OnLoaded()
{
const int btnSize = 35;
var c = 0;
for (var i = 65; i <= 90; i++)
{
var btn = new Button {
Content = (char) i,
Click += GuessClick()
};
btn.Width = btn.Height = btnSize;
var margin = btn.Margin;
margin.Left = c += 37;
btn.Margin = margin;
GridMain.Children.Add(btn);
}
}
private void GuessClick(object sender, EventArgs e) {
var choice = sender as Button;
if (choice == null || !copyCurrent.Contains(choice.DataContext.ToString())) return;
var temp = copyCurrent.ToCharArray();
var find = copyCurrent.ToCharArray();
var guessChar = choice.DataContext.ToString().ElementAt(0);
for (var index = 0; index < find.Length; index++) {
if (find[index] == guessChar) {
temp[index] = guessChar;
}
}
copyCurrent = new string(temp);
DisplayTheWord();
}
I will take a stab at "Psychic Debugging" this code. There are lots of things that can be improved, changed, etc, but I am guessing this is where you may be having an issue:
var temp = copyCurrent.ToCharArray();
var find = copyCurrent.ToCharArray();
var guessChar = choice.DataContext.ToString().ElementAt(0);
for (var index = 0; index < find.Length; index++) {
if (find[index] == guessChar) {
temp[index] = guessChar;
}
}
copyCurrent = new string(temp);
No matter what the guessChar is, at the end of this block of code copyCurrent will be unchanged (as far as what the actual string content of copyCurrent is). First you make two arrays that are identical. Then you are looping through the find array looking for the guessChar. If you find the guessChar then you are "modifying" the temp array to have guessChar at the very same index where you found it in find. Since both arrays are identical, the end result is that no "change" takes place. Once you have executed the loop you are creating a new string from the temp array, but since both find and temp are identical and unchanged after this loop, you effectively are making a new string that is identical to the one you started with. I don't know what you are expecting this code to do, but I am assuming this is not it.
I am going to assume (from the load method name) that this is a game of hangman and that at the outset of the game copyCurrent has some content like "????" and that you have some other variable, maybe called answer and it would have the content, for example, "food". If that is the case, then you would just need to modify these two lines:
var temp = copyCurrent.ToCharArray();
var find = answer.ToCharArray();
I want to assign value to elements of my array. after running this, all elements of ListResults are same as last element of ListROI.
ListResults = new DataPoint[nROIrow];
DataPoint TempRes = new DataPoint();
System.Collections.ArrayList List = new System.Collections.ArrayList();
for (int i = 0; i < nROIrow; i++)
{
TempRes.X = ListROI[i].X;
TempRes.Y = ListROI[i].Y;
TempRes.u = dispROIcorr[i, 0];
TempRes.v = dispROIcorr[i, 1];
ListResults[i] = TempRes;
disp.Xpix = ListResults[i].X;
disp.Ypix = ListResults[i].Y;
disp.X = ListResults[i].X;
disp.Y = ListResults[i].Y;
disp.U = ListResults[i].u;
disp.V = ListResults[i].v;
List.Add(disp);
bSAVE.Enabled = true;
}
You only create a new DataPoint(); one time. So you end up with an array full of references to that same single instance.
The simple fix:
ListResults = new DataPoint[nROIrow];
//DataPoint TempRes = new DataPoint();
System.Collections.ArrayList List = new System.Collections.ArrayList();
for (int i = 0; i < nROIrow; i++)
{
DataPoint TempRes = new DataPoint();
...
ListResults[i] = TempRes;
var disp = new ...
disp.Xpix = ListResults[i].X;
....
List.Add(disp);
}
The problem with your code is that you are reusing the TempRes variable. When you perform the "List.Add" you are just adding a reference to it, and all these references are (obviously) the same. You also modify it, so each identical reference logically points to the same identical data.
Instead, write:
System.Collections.ArrayList List = new System.Collections.ArrayList();
for (int i = 0; i < nROIrow; i++)
{
DataPoint TempRes = new DataPoint();
...
Note also that ArrayList is generally considered to be deprecated since .NET 2.0 and you should be using List<T> instead.
do
disp = new ... // whatever
before assigning values to disp[i].???
actually what is happening is all the references in your List are referring to disp which is the single object that was created outside the for loop, hence all items in List are pointing to same disp object, hence same values.
Below is my code,
List<float?> LValues = new List<float?>();
List<float?> IValues = new List<float?>();
List<float?> BValues = new List<float?>();
List<HMData>[] data = new List<HMData>[4];
List<HMData>[] Data = new List<HMData>[7];
float? Value_LfromList = 0;
float? Value_IfromList = 0;
float? Value_BfromList = 0;
int indexer=0;
foreach (var item in Read_xml_for_childobjects_id.Root.Descendants("object"))
{
data[indexer] = new List<HMData>(); // Error occuring on this line
for (int k = 0; k < 7; k++)
{
Value_LfromList = LValues.ElementAt(k);
Value_IfromList = IValues.ElementAt(k);
Value_BfromList = BValues.ElementAt(k);
Data[k].Add(new HMData { x = Value_LfromList, y = Value_IfromList, z = Value_BfromList });
}
indexer++;
}
As soon as I intend to add the element at Data list in following line,
Data[k].Add(new HMData { x = Value_LfromList, y = Value_IfromList, z = Value_BfromList });
I get an error as Object reference not set to instant of object,
I want output be as shown in following question link,
Result required as shown in this question,
I have tried by lots of ways but could not make it,will really appreciate help if provided,Thanks.
Your code is a nightmare. You should really think about refactoring...
You have to initialize the lists within Data array.
List<HMData>[] Data = new List<HMData>[7];
for(int i = 0; i < 7; i++)
Data[i] = new List<HMData>();
There are tons of other problems and questions that should be asked (like what's the difference between data and Data?, why are these array sized explicitly?). Without that knowledge every advice can be not enough to solve your real problem.
you just need to declare the list as
List<HMData> Data = new List<HMData>();
and add new element to the list by
Data.Add(new HMData { x = Value_LfromList, y = Value_IfromList, z = Value_BfromList });
SubnetConvert SubnetOctet1 = new SubnetConvert();
SubnetConvert SubnetOctet2 = new SubnetConvert();
SubnetConvert SubnetOctet3 = new SubnetConvert();
SubnetConvert SubnetOctet4 = new SubnetConvert();
int Octet1 = int.Parse(txtOctet1.Text);
SubnetOctet1.OctetConvert = Octet1;
lblOctet1.Text = SubnetOctet1.SendBinary;
int Octet2 = int.Parse(txtOctet2.Text);
SubnetOctet2.OctetConvert = Octet2;
lblOctet2.Text = SubnetOctet1.SendBinary;
int Octet3 = int.Parse(txtOctet3.Text);
SubnetOctet3.OctetConvert = Octet3;
lblOctet3.Text = SubnetOctet1.SendBinary;
int Octet4 = int.Parse(txtOctet4.Text);
SubnetOctet4.OctetConvert = Octet4;
lblOctet4.Text = SubnetOctet1.SendBinary;
is it possible to put all this code in a For loop like
For (int i = 1; i <=4; i++)
{
SubnetConvert SubnetOctet[i] = new SubnetConvert();
int Octet[i] = int.Parse(txtOctet[i].Text);
SubnetOctet[i].OctetConvert = Octet[i];
lblOctet[i].Text = SubnetOctet[i].SendBinary;
}
I have tried the coding above and it doesn't work, I have just put it there for an example of what I want to achieve
The code sample is not something possible - there is no support for control arrays as you have shown.
A better way would be to write a function that encapsulates the repeating code and pass in the differing parameters.
private void SetBinaryValue(string value, Label display)
{
int Octet = int.Parse(value);
SubnetOctet.OctetConvert = Octet;
display.Text = SubnetOctet.SendBinary;
}
You would call this function like so:
SetBinaryValue(txtOctet1.Text, lblOctet1);
SetBinaryValue(txtOctet2.Text, lblOctet2);
Note that you only need one SubnetConvert with this approach (which you can either initialize within the function, or as a field).
It's perfectly possible to loop through named controls using FindControl:
var subnetOctet = new SubnetConvert();
for (int i = 1; i <= 4; ++i) {
// ID suffix as string
var indexText = i.ToString(CultureInfo.InvariantCulture);
// ID of TextBox and Label
var textBoxId = "txtOctet" + indexText;
var labelId = "lblOctet" + indexText;
// The TextBox and the Label
var textBox = (TextBox)FindControl(textBoxId);
var label = (Label)FindControl(labelId);
// Parse the value into an int
int octet = int.Parse(textBox.Text);
subnetOctet.OctetConvert = octet;
// Update the TextBox's Test
label.Text = subnetOctet.SendBinary;
}
One advantage to using this method is that you can add more controls on the fly, or even programmatically, and if you keep track of the number of subnets you need to handle, you do not have to update your code.
You could also create an Array with the your objects as the elements and then loop through the array and execute the functions based on the array position at loop position;
Dog pet1 = new Dog();
Dog pet2 = new Dog();
Dog pet3 = new Dog();
Dog pet4 = new Dog();
//create a list of pets and add your pets to them
List<Dog> pets = new List<Dog>();
pets.Add(pet1);
pets.Add(pet2);
pets.Add(pet3);
pets.Add(pet4);
//Using a for each loop to go through each element in the array and execute identical actions on each
//element
foreach (Dog pet in pets)
{
pet.SetName("Fido");
}
//or create a for each loop that will allow you to know the position
//you are currenly at in the arry as the integer of i increments in the loop
for (int i = 0; i <= pets.Count; i++)
{
pets[i].SetName("Fido");
}
Ideally what you will want to do is create a single object and insert multiple instances of the object into the list via another loop and then use the foreach or the for loop to access an element of the list to manipulate a singular instance.
Dog dog = new Dog();
//create a list of pets and add your pets to them
List<Dog> pets = new List<Dog>();
for (int i = 0; i <= 5; i++)
{
pets.Add(dog);
}
//Using a for each loop to go through each element in the array and execute identical actions on each
//element
foreach (Dog pet in pets)
{
pet.SetName("Fido");
}