For Loop: i in variable names - c#

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");
}

Related

Error Index was out of range. Must be non-negative and less than the size of the collection

I am trying to fill my DTO objects with for, but I got this error:
Index was out of range. Must be non-negative and less than the size of the collection
Here is my code:
public static List <BankDepositHistoryDTO> DtoTODomain()
{
MyketAdsEntities context = new MyketAdsEntities();
List<BankDepositHistoryDTO> bdto = new List<BankDepositHistoryDTO>();
//var transactionlist
var transactionlist = GetListoftransactions.GetAccountingListoftransactions();
for (int i = 0; i < transactionlist.Count; i++)
{
bdto[i].AccountId = transactionlist[i].AccountId;
bdto[i].Id = transactionlist[i].Id;
bdto[i].Amount = transactionlist[i].Amount;
bdto[i].AdditionalData = transactionlist[i].AdditionalData;
bdto[i].ClientIp = transactionlist[i].ClientIp;
bdto[i].Gateway = transactionlist[i].Gateway;
bdto[i].PaymentRefNumber = transactionlist[i].PaymentRefNumber;
bdto[i].ReturnUrl = transactionlist[i].ReturnUrl;
bdto[i].State = transactionlist[i].State;
bdto[i].Uuid = transactionlist[i].Uuid;
}
return bdto;
}
I got this message at here
bdto[i].AccountId = transactionlist[i].AccountId;
You've created an empty list, and aren't adding elements to it. You must first add an element, and then update its properties:
for (int i = 0; i < transactionlist.Count; i++)
{
BankDepositHistoryDTO b = new BankDepositHistoryDTO();
b.AccountId = transactionlist[i].AccountId;
b.Id = transactionlist[i].Id;b
b.Amount = transactionlist[i].Amount;
b.AdditionalData = transactionlist[i].AdditionalData;
b.ClientIp = transactionlist[i].ClientIp;
b.Gateway = transactionlist[i].Gateway;
b.PaymentRefNumber = transactionlist[i].PaymentRefNumber;
b.ReturnUrl = transactionlist[i].ReturnUrl;
b.State = transactionlist[i].State;
b.Uuid = transactionlist[i].Uuid;
bdto.Add(b);
}
Well obvously, bdto length is less than transactionlist length.
before your for loop you can resize bdto to match transactionlist
I totally agree with #Ashkan and #Mureinik's answer, but just to improve code you can use AutoMapper. It will reduce loop and iteration for every element. It seems that all the properties between these two objects is the same.
Mapper.CreateMap<Transaction,BankDepositHistoryDTO>();
BankDepositHistoryDTO obj = Mapper.Map<Transaction,BankDepositHistoryDTO>(TransactionObj);
Also if GetListoftransactions.GetAccountingListoftransactions(); returns List<BankDepositHistoryDTO>, you can directly return that object in method.

Avoiding duplicates in List within loop

I have a for loop which invokes a method within it. I add the return of this method to a list however I am getting duplicates in the list (the last return from the method call is all the items in the list). Presumably this is because the result object is the same instance. Is there a way around this?
IList<CarResult> carResults = new List<CarResult>();
for (int i = 0; i < cars.Count(); i++)
{
result = calculation.RunForCar(
engineSize[i],
yearOfManufacture[i],
carResults.Add(result);
}
return carResults;
}
I'm going to make a qualified guess and try to explain what's going on, without knowing exactly what's happening in your RunForCar().
Presumably this is because the result object is the same instance.
Probably yes.
Here's an example. It will not create new instances of Foo, but re-use the same instance over and over. So every time the name changes it changes the name on the reference. The list itself only contains the references, and therefore all the items in the list will be changed if you change the name on the reference.
var list = new List<Foo>();
var result = new Foo();
for(int i = 0; i < 5; i++)
{
result.Name = i.ToString();
list.Add(result);
}
foreach (var foo in list)
{
Console.WriteLine(foo.Name);
}
Output:
4
4
4
4
4
If we instead do like the code below, we assign result to a new reference, and then we leave the existing references untouched.
var list = new List<Foo>();
var result = new Foo();
for(int i = 0; i < 5; i++)
{
result = new Foo()
{
Name = i.ToString()
};
result.Name = i.ToString();
list.Add(result);
}
foreach (var foo in list)
{
Console.WriteLine(foo.Name);
}
Output:
0
1
2
3
4
Is there a way around this?
Yes, you can simply create a new instance of result for every loop. Without knowing more about either CarResult or RunForCar I cannot say when it's best to create the new instance. But here's an example:
IList<CarResult> carResults = new List<CarResult>();
for (int i = 0; i < cars.Count(); i++)
{
result = new CarResult();
result = calculation.RunForCar(
engineSize[i],
yearOfManufacture[i]); // Fixed type-o?
carResults.Add(result);
}
return carResults;
Alternatively you can have a local variable inside the loop.
IList<CarResult> carResults = new List<CarResult>();
for (int i = 0; i < cars.Count(); i++)
{
var result = new CarResult(); // Will not be accessible outside of loop.
result = calculation.RunForCar(
engineSize[i],
yearOfManufacture[i]); // Fixed type-o?
carResults.Add(result);
}
return carResults;
If the result is the same instance, you need to replace IList with HashSet
You need to create a new instance or result object on every pass of the loop in order to avoid adding it by reference to carResults list. Oterwise, all items in carResults will hold the reference to the same object which will contain the data from the last loop cycle.

How to Merge items within a List<> collection C#

I have a implememtation where i need to loop through a collection of documents and based on certain condition merge the documents .
The merge condition is very simple, if present document's doctype is same as later document's doctype, then copy all the pages from the later doctype and append it to the pages of present document's and remove the later document from the collection.
Note : Both response.documents and response.documents[].pages are List<> collections.
I was trying this but was getting following exception Once I remove the document.
collection was modified enumeration may not execute
Here is the code:
int docindex = 0;
foreach( var document in response.documents)
{
string presentDoctype = string.Empty;
string laterDoctype = string.Empty;
presentDoctype = response.documents[docindex].doctype;
laterDoctype = response.documents[docindex + 1].doctype;
if (laterDoctype == presentDoctype)
{
response.documents[docindex].pages.AddRange(response.documents[docindex + 1].pages);
response.documents.RemoveAt(docindex + 1);
}
docindex = docindex + 1;
}
Ex:
reponse.documents[0].doctype = "BankStatement" //page count = 1
reponse.documents[1].doctype = "BankStatement" //page count = 2
reponse.documents[2].doctype = "BankStatement" //page count = 2
reponse.documents[3].doctype = "BankStatement" //page count = 1
reponse.documents[4].doctype = "BankStatement" //page count = 4
Expected result:
response.documents[0].doctype = "BankStatement" //page count = 10
Please suggest.Appreciate your help.
I would recommend you to look at LINQ GroupBy and Distinct to process your response.documents
Example (as I cannot use your class, I give example using my own defined class):
Suppose you have DummyClass
public class DummyClass {
public int DummyInt;
public string DummyString;
public double DummyDouble;
public DummyClass() {
}
public DummyClass(int dummyInt, string dummyString, double dummyDouble) {
DummyInt = dummyInt;
DummyString = dummyString;
DummyDouble = dummyDouble;
}
}
Then doing GroupBy as shown,
DummyClass dc1 = new DummyClass(1, "This dummy", 2.0);
DummyClass dc2 = new DummyClass(2, "That dummy", 2.0);
DummyClass dc3 = new DummyClass(1, "These dummies", 2.0);
DummyClass dc4 = new DummyClass(2, "Those dummies", 2.0);
DummyClass dc5 = new DummyClass(3, "The dummies", 2.0);
List<DummyClass> dummyList = new List<DummyClass>() { dc1, dc2, dc3, dc4, dc5 };
var groupedDummy = dummyList.GroupBy(x => x.DummyInt).ToList();
Will create three groups, marked by DummyInt
Then to process the group you could do
for (int i = 0; i < groupedDummy.Count; ++i){
foreach (DummyClass dummy in groupedDummy[i]) { //this will process the (i-1)-th group
//do something on this group
//groupedDummy[0] will consists of "this" and "these", [1] "that" and "those", while [2] "the"
//Try it out!
}
}
In your case, you should create group based on doctype.
Once you create groups based on your doctype, everything else would be pretty "natural" for you to continue.
Another LINQ method which you might be interested in would be Distinct. But I think for this case, GroupBy would be the primary method you would like to use.
Use only "for loop" instead of "foreach".
foreach will hold the collection and cannot be modified while looping thru it.
Here is an example using groupBy, hope this help.
//mock a collection
ICollection<string> collection1 = new List<string>();
for (int i = 0; i < 10; i++)
{
collection1.Add("BankStatement");
}
for (int i = 0; i < 5; i++)
{
collection1.Add("BankStatement2");
}
for (int i = 0; i < 4; i++)
{
collection1.Add("BankStatement3");
}
//merge and get count
var result = collection1.GroupBy(c => c).Select(c => new { name = c.First(), count = c.Count().ToString() }).ToList();
foreach (var item in result)
{
Console.WriteLine(item.name + ": " + item.count);
}
Just use AddRange()
response.documents[0].pages.AddRange(response.documents[1].pages);
it will merge all pages of document[1] with the document[0] into document[0]

After loop all elements same

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.

How to set array length in c# dynamically

I am still new to C# and I've been struggling with various issues on arrays. I've got an array of metadata objects (name value pairs) and I would like to know how to create only the number of "InputProperty" objects that I truly need. In this loop I've arbitrarily set the number of elements to 20 and I try to bail out when the entry becomes null but the web service on the receiving end of this does not like any null elements passed to it:
private Update BuildMetaData(MetaData[] nvPairs)
{
Update update = new Update();
InputProperty[] ip = new InputProperty[20]; // how to make this "dynamic"
int i;
for (i = 0; i < nvPairs.Length; i++)
{
if (nvPairs[i] == null) break;
ip[i] = new InputProperty();
ip[i].Name = "udf:" + nvPairs[i].Name;
ip[i].Val = nvPairs[i].Value;
}
update.Items = ip;
return update;
}
In summary, say I only have 3 namevalue pairs in the above input array? Rather than allocate 20 elements for the array called ip, how can code this so ip is only as big as it needs to be. The update object is passed across another webservice so serialization is important (i.e. I can't use namevaluecollection, etc.).
p.s. Is the only way to followup on a posted question through the "add comments" facility?
InputProperty[] ip = new InputProperty[nvPairs.Length];
Or, you can use a list like so:
List<InputProperty> list = new List<InputProperty>();
InputProperty ip = new (..);
list.Add(ip);
update.items = list.ToArray();
Another thing I'd like to point out, in C# you can delcare your int variable use in a for loop right inside the loop:
for(int i = 0; i<nvPairs.Length;i++
{
.
.
}
And just because I'm in the mood, here's a cleaner way to do this method IMO:
private Update BuildMetaData(MetaData[] nvPairs)
{
Update update = new Update();
var ip = new List<InputProperty>();
foreach(var nvPair in nvPairs)
{
if (nvPair == null) break;
var inputProp = new InputProperty
{
Name = "udf:" + nvPair.Name,
Val = nvPair.Value
};
ip.Add(inputProp);
}
update.Items = ip.ToArray();
return update;
}
If you don't want to use a List, ArrayList, or other dynamically-sized collection and then convert to an array (that's the method I'd recommend, by the way), then you'll have to allocate the array to its maximum possible size, keep track of how many items you put in it, and then create a new array with just those items in it:
private Update BuildMetaData(MetaData[] nvPairs)
{
Update update = new Update();
InputProperty[] ip = new InputProperty[20]; // how to make this "dynamic"
int i;
for (i = 0; i < nvPairs.Length; i++)
{
if (nvPairs[i] == null) break;
ip[i] = new InputProperty();
ip[i].Name = "udf:" + nvPairs[i].Name;
ip[i].Val = nvPairs[i].Value;
}
if (i < nvPairs.Length)
{
// Create new, smaller, array to hold the items we processed.
update.Items = new InputProperty[i];
Array.Copy(ip, update.Items, i);
}
else
{
update.Items = ip;
}
return update;
}
An alternate method would be to always assign update.Items = ip; and then resize if necessary:
update.Items = ip;
if (i < nvPairs.Length)
{
Array.Resize(update.Items, i);
}
It's less code, but will likely end up doing the same amount of work (i.e. creating a new array and copying the old items).
Use this:
Array.Resize(ref myArr, myArr.Length + 5);
Does is need to be an array? If you use an ArrayList or one of the other objects available in C#, you won't have this limitation to content with. Hashtable, IDictionnary, IList, etc.. all allow a dynamic number of elements.
You could use List inside the method and transform it to an array at the end. But i think if we talk about an max-value of 20, your code is faster.
private Update BuildMetaData(MetaData[] nvPairs)
{
Update update = new Update();
List<InputProperty> ip = new List<InputProperty>();
for (int i = 0; i < nvPairs.Length; i++)
{
if (nvPairs[i] == null) break;
ip[i] = new InputProperty();
ip[i].Name = "udf:" + nvPairs[i].Name;
ip[i].Val = nvPairs[i].Value;
}
update.Items = ip.ToArray();
return update;
}
Or in C# 3.0 using System.Linq you can skip the intermediate list:
private Update BuildMetaData(MetaData[] nvPairs)
{
Update update = new Update();
var ip = from nv in nvPairs
select new InputProperty()
{
Name = "udf:" + nv.Name,
Val = nv.Value
};
update.Items = ip.ToArray();
return update;
}
Use Array.CreateInstance to create an array dynamically.
private Update BuildMetaData(MetaData[] nvPairs)
{
Update update = new Update();
InputProperty[] ip = Array.CreateInstance(typeof(InputProperty), nvPairs.Count()) as InputProperty[];
int i;
for (i = 0; i < nvPairs.Length; i++)
{
if (nvPairs[i] == null) break;
ip[i] = new InputProperty();
ip[i].Name = "udf:" + nvPairs[i].Name;
ip[i].Val = nvPairs[i].Value;
}
update.Items = ip;
return update;
}
Typically, arrays require constants to initialize their size. You could sweep over nvPairs once to get the length, then "dynamically" create an array using a variable for length like this.
InputProperty[] ip = (InputProperty[])Array.CreateInstance(typeof(InputProperty), length);
I wouldn't recommend it, though. Just stick with the
List<InputProperty> ip = ...
...
update.Items = ip.ToArray();
solution. It's not that much less performant, and way better looking.
You can create an array dynamically in this way:
static void Main()
{
// Create a string array 2 elements in length:
int arrayLength = 2;
Array dynamicArray = Array.CreateInstance(typeof(int), arrayLength);
dynamicArray.SetValue(234, 0); // → a[0] = 234;
dynamicArray.SetValue(444, 1); // → a[1] = 444;
int number = (int)dynamicArray.GetValue(0); // → number = a[0];
int[] cSharpArray = (int[])dynamicArray;
int s2 = cSharpArray[0];
}

Categories

Resources