Ok, I cannot get this. I've looked at it and I don't see why it's out of bounds. I get the error at paypalItems[paypalItems.Length] = new PaymentDetailsItemType
PaymentDetailsItemType[] paypalItems = new PaymentDetailsItemType[order.OrderItems.Count];
for (int i = 0; i < order.OrderItems.Count; i++)
{
paypalItems[i] = new PaymentDetailsItemType
{
Name = order.OrderItems[i].Name,
Amount = ApiUtility.CreateBasicAmount(order.OrderItems[i].Price),
Description = order.OrderItems[i].Name,
Number = order.OrderItems[i].Sku,
};
}
// paymentItems now has 1 item...now to the if statement:
if (giftCardsTotal != 0)
{
// add Coupons & Discounts line item
paypalItems[paypalItems.Length] = new PaymentDetailsItemType
{
Name = "Gift Cards",
Amount = ApiUtility.CreateBasicAmount(giftCardsTotal),
Description = "Gift Cards"
};
}
UPDATED: I changed the size of the array..now it's all good. No need for the -1
PaymentDetailsItemType[] paypalItems = new PaymentDetailsItemType[order.OrderItems.Count + 1];
for (int i = 0; i < order.OrderItems.Count; i++)
{
paypalItems[i] = new PaymentDetailsItemType
{
Name = order.OrderItems[i].Name,
Amount = ApiUtility.CreateBasicAmount(order.OrderItems[i].Price),
Description = order.OrderItems[i].Name,
Number = order.OrderItems[i].Sku,
};
}
// paymentItems now has 1 item...now to the if statement:
if (giftCardsTotal != 0)
{
paypalItems[paypalItems.Length -1] = new PaymentDetailsItemType
{
Name = "Certificates",
Amount = ApiUtility.CreateBasicAmount(giftCardsTotal),
Description = "Certificates"
};
}
I think you might be better off using a List<>, so you would declare:
List<PaymentDetailsItemType> paypalItems = new List<PaymentDetailsItemType>();
Then when you iterate through order.OrderItems, just do a paypalItems.Add()
Finally on your if(giftCardsTotal != 0) conditional just do a:
paypalItems.Add(new PaymentDetailsItemType...);
This way you don't have to worry about off by one array indexing issues. Here would be the rewritten code (I use var for my convenience):
var paypalItems = new List<PaymentDetailsItemType>();
foreach (var orderitem in order.OrderItems)
{
paypalItems.Add(new PaymentDetailsItemType
{
Name = orderitem.Name,
Amount = ApiUtility.CreateBasicAmount(orderitem.Price),
Description = orderitem.Name,
Number = orderitem.Sku,
});
}
if (giftCardsTotal != 0)
{
// add Coupons & Discounts line item
paypalItems.Add(new PaymentDetailsItemType
{
Name = "Gift Cards",
Amount = ApiUtility.CreateBasicAmount(giftCardsTotal),
Description = "Gift Cards"
});
}
Per John Saunders' suggestion (in the comments), here's a Linq alterative to the variable declaration and first loop:
var paypalItems =
(from orderitem in order.OrderItems
select new PaymentDetailsItemType
{
Name = orderitem.Name,
Amount = ApiUtility.CreateBasicAmount(orderitem.Price),
Description = orderitem.Name,
Number = orderitem.Sku
}).ToList();
Addition based on comment: If you need an Array when you're done, call:
paypalItems.ToArray()
Arrays are zero-based in C#. Using array[array.Length] will always fail. You want Length-1.
In addition, I see that you're trying to expand the array. You can't do that! Once an array is instantiated, it's length cannot change.
If you need a collection that can expand, use List<PaymentDetailsItemType>.
Because they are 0-indexed, so first one is the 0 and last one is length-1.
This is true for almost any programming language..
It seems that first you fill up an array by trasforming elements from another one and then you want to replace last one. Maybe you intended to append an element to the end?
In that case you should build it larger:
PaymentDetailsItemType[] paypalItems = new PaymentDetailsItemType[order.OrderItems.Count+1];
then fill it as you did:
for (int i = 0; i < order.OrderItems.Count; i++)
{
...
}
then set the last one:
paypalItems[paypalItems.Length-1] = ..
paypalItems[paypalItems.Length] =
should be
paypalItems[paypalItems.Length - 1] =
This:
paypalItems[paypalItems.Length]
Will always be outside the bounds of the array as the array index starts at 0. If you want to store something in the last element of the array do:
paypalItems[paypalItems.Length-1] = ...
It looks like you're trying to append to the array by simply using the next index. Perhaps you learned this from exposure to a language like javascript or python, where "arrays" are really complex objects. Real arrays don't work like that.
Instead, you should try using the .Add() method of List<PaymentDetailsItemType>.
You need to change the size of array before add a new array item.
if (giftCardsTotal != 0)
{
// Increase the size
Array.Resize(ref paypalItems, paypalItems.Length + 1);
// add Coupons & Discounts line item
paypalItems[paypalItems.Length -1] = new PaymentDetailsItemType
{
Name = "Gift Cards",
Amount = ApiUtility.CreateBasicAmount(giftCardsTotal),
Description = "Gift Cards"
};
}
Length starts from 1 and index from 0. So you should try:
paypalItems[paypalItems.Length - 1]
You are initializing the array to the length of order.OrderItems.Count then after filling it up with data, you are trying to add an additional item to the array. This won't work like this. You have allocated a static size to the array here, you can't add an additional item to that without some sort of reallocation.
You need to create a dynamically allocated array or use a List<T>
To add to the other answers, an Array in .NET is a low-level data type that maps directly to an allocated sequence of bytes in memory. Thus, you cannot add items to an array if it's already full. Maybe what you're looking for is to use a List<T>:
var paypalItems = new List<PaymentDetailsItemType>(order.OrderItems.Count);
// specifying that count is optional, but will increase performance because array space will have to be reallocated less often
// ...
paypalItems.Add(new PaymentDetailsItemType
{
Name = "Gift Cards",
Amount = ApiUtility.CreateBasicAmount(giftCardsTotal),
Description = "Gift Cards"
});
paypalItems[paypalItems.Length] would access one position above the allocated space. If you want the last position you need paypalItems[paypalItems.Length-1]
If you want to append an item use a List<> instead of an array.
Related
I have an ArrayList with multiples items on it, everyone of them is a String divided by commas "loglogs", the three first items are the localization (Destin, lat and long). I need to insert the Strings of these loglogs in buttons depending on its localization (based on that three parameters) in the button Tooltip or text programatically. I have all the button creation but I have to add the strings but there are more loglogs than buttons so...
I need to "filter" the ArrayList into another ArrayList, filter it depending on these three inital coordinates, I want to create another ArrayList but appending the strings that are identical in their three first elements of the arrayList. That way I will combine the "loglogs" into another "loglogsCondensed", with all the "localization" unique so I can add this part to my button and index creation.
foreach (String log in logslogs)
{
String[] colContent = log.Split(','); //splited the content with commas
Loglog log = new Loglog(); //Loglog is a class of logs with information in specific columns
log.Destin = colContent[0];
log.Lat = Convert.ToChar(colContent[1]);
log.Long = colContent[2];
log.Barcode = colContent[6];
log.Source = colContent[7];
log.SampleName = colContent[9];
AllLogs.Add(log);
I need to pass from logslogs with 1000 memebers to an ArrayList with less items, where the ones with the same location based on the three first items are appended as one item.
Suposse this is kind of easy if you know how to code properly (not my case). A thousand thanks only for read this out, even more to the people who try to help.
Best,
I have the solution!, probably is not going to win any contest of cleaneness but it does what I need!. I create an index to filter comparing the items depending of the three coordinates: Destin, Long and Lat. If they are the same I remove the last item and put the appended line in the last place and so on...
int c = 0; //Just to go the first time
//We create an index to compare the former with the "actual"
//log in every loop of the "foreach"
String IndiceDestin0 = string.Empty;
String IndiceLat0 = string.Empty;
String IndiceLong0 = string.Empty;
String IndiceDestin1;
String IndiceLat1;
String IndiceLong1;
foreach (String log in logslogs)
{
String[] LongContent = log.Split(',');
Loglog log = new Loglog();
log.Destin = LongContent[0];
log.Lat = Convert.ToChar(LongContent[1]);
log.Long = LongContent[2];
log.Barcode = LongContent[6];
log.Source = LongContent[7];
log.DestDestinBarcode = LongContent[8];
log.SampleName = LongContent[9];
AllLogs.Add(log);
//This only works once, the first time because we don't have a "former" data to compare we have to bypass the comparison
if (c == 0)
{
IndiceDestin0 = LongContent[0];
IndiceLat0 = LongContent[1];
IndiceLong0 = LongContent[2];
c++;
}
else
{
IndiceDestin1 = LongContent[0];
IndiceLat1 = LongContent[1];
IndiceLong1 = LongContent[2];
if (IndiceDestin0.Equals(IndiceDestin1) && IndiceLat0.Equals(IndiceLat1) && IndiceLong0.Equals(IndiceLong1))
{
int last = logsToButtons.Count - 1;
string oldLog = logsToButtons[last].ToString();
string appendedLog = oldLog + log;
//We remove the last "single" log to add the aggregated log
logsToButtons.RemoveAt(last);
logsToButtons.Add(appendedLog);
}
else
{
logsToButtons.Add(log);
}
IndiceDestin0 = IndiceDestin1;
IndiceLat0 = IndiceLat1;
IndiceLong0 = IndiceLong1;
c++;
}
}
I get to have a shorter version of the array but appending together the ones that have the same coordenates, thank you everybody for your help, I know is messy but it works!
Best,
I am getting "index out of range" from this loop. But I need to use new elements that loop founds, how do I do that? Please help to fix the problem
int linkCount = driver.FindElements(By.CssSelector("a[href]")).Count;
string[] links = new string[linkCount];
for (int i = 0; i < linkCount; i++)
{
List<IWebElement> linksToClick = driver.FindElements(By.CssSelector("a[href]")).ToList();
links[i] = linksToClick[i].GetAttribute("href");
}
I think that you could refactor your code:
var linkElements = driver.FindElements(By.CssSelector("a[href]")).ToList();
var links = new List<string>();
foreach (var elem in linkElements)
{
links.Add(elem.GetAttribute("href"));
}
If that works, you could simplify the query:
var instantLinks = driver.FindElements(By.CssSelector("a[href]"))
.Select(e => e.GetAttribute("href"))
.ToList();
You can rewrite your code to bypass the for loop:
string[] links = driver.FindElements(By.CssSelector("a[href]")).Select(l => l.GetAttribute("href")).ToArray();
This should also avoid the index out of range problem, and cut down the amount of code you have to write.
First of all i dont see a point in assigning linkstoclick values inside loop... And Reason for error must be that linksToClick list's length is more than that of linkCount.
int linkCount = driver.FindElements(By.CssSelector("a[href]")).Count;
List<string> links = new List<string>();
for (int i = 0; i < linkCount; i++)
{
List<IWebElement> linksToClick = driver.FindElements(By.CssSelector("a[href]")).ToList();
if (linksToClick.Count < i)
links.Add(linksToClick[i].GetAttribute("href"));
}
This might help with the out of range exception.
Doing this allows you to create a list of type: string without having to explicitly define the size of the list
the first one gets all of your elements by tag name ...let's assume 5.
in the loop, your driver get's all the elements by css selector, and you might have a different number here. let's say 4.
then, you might be trying to set the fifth element in a four element array.
boom.
Easiest fix to debug:
int linkCount = driver.FindElements(By.TagName("a")).Count;
string[] links = new string[linkCount];
// WRITE OUT HOM MANY links you have
for (int i = 0; i < linkCount; i++)
{
List<IWebElement> linksToClick = driver.FindElements(By.CssSelector("a[href]")).ToList();
// ASSERT THAT YOU HAVE THE SAME AMOUNT HERE
If (links.Count != linksToClick.Count)
// your logic here
links[i] = linksToClick[i].GetAttribute("href");
}
I am getting indexoutofrangeexception (see ----> pointer for the line generating the error down below in the code). The program loops through the header and line item records in a dataset tables. The tables have a relationship. My sample data has 2 headers, each with 2 lines. The progam has two loops, the first one loops through the header records and the second one loops through the child records of the header.
Part of the program:
// ***** PO Header and Line
int ln;
ln = 0;
// Create an eConnect PO Header node object
taGLTransactionHeaderInsert jeh = new taGLTransactionHeaderInsert();
// Create an array for lineitems
taGLTransactionLineInsert_ItemsTaGLTransactionLineInsert[] lineitems = new taGLTransactionLineInsert_ItemsTaGLTransactionLineInsert[ln];
foreach (DataRow dtrHDR in ds.Tables["Header"].Rows)
{
Array.Clear(lineitems, 0, ln);
jeh.BACHNUMB = "Sheraz";
jeh.JRNENTRY = jenoint;
jeh.REFRENCE = dtrHDR["Reference"].ToString();
jeh.SOURCDOC = dtrHDR["AvantisJE"].ToString();
jeh.USERID = System.Environment.UserName;
jeh.TRXDATE = System.DateTime.Now.ToString();
ln = 0;
foreach (DataRow dtrLine in dtrHDR.GetChildRows("HdrLine"))
{
// Populate the elements of the taPoLIne_ItemsTaPOLine XML node
taGLTransactionLineInsert_ItemsTaGLTransactionLineInsert jel = new taGLTransactionLineInsert_ItemsTaGLTransactionLineInsert();
jel.BACHNUMB = jeh.BACHNUMB;
jel.JRNENTRY = jeh.JRNENTRY;
jel.ACTNUMST = dtrLine["GreatPlains"].ToString();
jel.DEBITAMT = Convert.ToDecimal(dtrLine["Debit"].ToString());
//Avantis Inv Trx Key
jel.ORDOCNUM = dtrLine["AvantisJE_Line"].ToString();
// Avantis GL Trx Type
jel.ORTRXDESC = dtrLine["transactiontypename"].ToString();
//Add POLine to an Array
lineitems[ln] = jel; ----------------> I get an error here!
ln = ln + 1;
Array.Resize(ref lineitems, ln + 1);
}
}
You are accessing an index that doesn't yet exist.
//Add POLine to an Array
lineitems[ln] = jel; ----------------> I get an error here!
ln = ln + 1;
Array.Resize(ref lineitems, ln + 1);
You need to change the order to :
//Add POLine to an Array
Array.Resize(ref lineitems, ln + 1);
lineitems[ln] = jel; ----------------> should be fixed, no error here!
ln = ln + 1;
EDIT: Now that the immediate problem is out of the way, on to a better implementation.
Arrays are of a fixed sized, resizing an array is an expensive operation (basically it entails creating a copy with a new size). typically you would use these after identifying a performance bottle neck. In most cases it would be much better to use a List.
I'd recommend changing this line:
// Create an array for lineitems
taGLTransactionLineInsert_ItemsTaGLTransactionLineInsert[] lineitems =
new taGLTransactionLineInsert_ItemsTaGLTransactionLineInsert[ln];
to:
var lineitems = new List<taGLTransactionLineInsert_ItemsTaGLTransactionLineInsert>();
and then to add to it you simply do
lineitems.Add(jel);
to iterate over them would be:
for (var ln in lineitems) {
// whatever you want to do with a line.
}
to acccess a specific item by index would be:
lineitems.Item(i); // get the ith item in the list.
This is because you created an array with 0 elements and try to insert an element on position 0. This will not work. You can fix it by declaring the array with a size of 1 to begin with:
// Create an array for lineitems
taGLTransactionLineInsert_ItemsTaGLTransactionLineInsert[] lineitems = new taGLTransactionLineInsert_ItemsTaGLTransactionLineInsert[1];
However, resizing an array on the fly is not the idiomatic .NET way of doing this. You could use a List<T>, which takes care of resizing for you, and leaving you with cleaner code and possibly better performance.
It appears that you're trying to increase the size of the array by setting a value, like you might do in JavaScript. C# arrays are not like that. You need to create them at the size you want them to be when finished.
Alternately, you could use a List object, using the Add() method to put new content into the list.
lineitems is obviously not the same size as the row collection returned by dtrHDR.GetChildRows("HdrLine"). You are creating an array of zero elements and then trying to index into it. If you want it to match the size of dtrHDR.GetChildRows("HdrLine") then you need to call that first and initialize the array after you can get the count.
Instead of using an array why don't you use a List<T> and just push items onto it? No need to worry about IndexOutOfRange exceptions anymore.
You need to initialize the array before putting anything in to it. call the .resize first.
those lines are the problem
int ln;
ln = 0;
// Create an array for lineitems
taGLTransactionLineInsert_ItemsTaGLTransactionLineInsert[] lineitems = new taGLTransactionLineInsert_ItemsTaGLTransactionLineInsert[ln];
You create table of 0 elements.
You have an off-by-one error in your program:
int ln = 0
.
.
.
taGLTransactionLineInsert_ItemsTaGLTransactionLineInsert[] lineitems = new taGLTransactionLineInsert_ItemsTaGLTransactionLineInsert[ln];
.
.
.
lineitems[ln] = jel;
You are initializing an array of 0 elements, then trying to set the first element (element[0]) to a value.
I am trying to make a 1d array of lists. I make it like this:
public static List<string>[] words = new List<string>[30];
public static List<string>[] hints = new List<string>[30];
And I call it like this:
foreach (string item in vars.directory)
{
reader2 = new StreamReader(item);
while (reader2.Peek() > 0)
{
string line = reader2.ReadLine();
if (line.StartsWith("#"))
{
vars.words[counter].Add(line.Substring(1, line.Length - 1)); //here
}
else if (line.StartsWith("-"))
{
vars.hints[counter].Add(line.Substring(1, line.Length - 1)); //another here
}
else if (line == "#end")
{
counter++;
}
}
}
I just wanted to add that vars is where I keep my public variables and that counter is indeed at 0 when the loop starts.
EDIT
In my haste I forgot to add the question... oops...
Here it is: When I call the add function (or any another function for that matter) it returns a null reference exception. How can I fix this?
I assume you're crashing when attempting to call .Add on your array element. You need to initialize your arrays with valid objects.
for( Int32 i = 0; i < vars.words.Length; ++i )
vars.words[i] = new List<string>();
for( Int32 i = 0; i < vars.hints.Length; ++i )
vars.hints[i] = new List<string>();
Why not just make a List<List<string>>, but yes you can make an array of lists
Using a list of lists, as already recommended, would make you escape your problems,
and it´s much more flexible and handy than your construction.
-> f.i. if the size of your data changes, you don´t have to change the list size, but the array
Here's a one-liner to initialize an array of lists of size 30:
static List<string>[] lists = (from i in Enumerable.Range(0, 30)
select new List<string>()).ToArray();
The problem is that array values are initialized to the default value, and the default value for reference types is null.
default(List<string>) returns null.
So, you'll need to re-initialize the objects in the array before you can access them, otherwise you will get a NullReferenceException.
One way to initialize all the objects in your array up front is to use this Linq statement:
const int sizeOfLists = 5;
List<string>[] lists = Enumerable.Range(0, sizeOfLists)
.Select(i => new List<string>())
.ToArray();
Another option is to initialize and add the sub-lists only when you need them, by using an outer List:
var lists = new List<List<string>>();
// ...
var aSubList = new List<string>();
lists.Add(aSubList);
This is particularly useful if you don't know the size of the outer set of lists up-front, and is still accessible by index.
(This was a comment before, but I made it an answer since many other answers got caught up in the solution and don't describe the problem)
You could initialize the lists right before you use them:
foreach (string item in vars.directory)
{
reader2 = new StreamReader(item);
while (reader2.Peek() > 0)
{
string line = reader2.ReadLine();
// new code
if (vars.words[counter] == null) vars.words[counter] = new List<string>();
if (vars.hints[counter] == null) vars.hints[counter] = new List<string>();
if (line.StartsWith("#"))
{
vars.words[counter].Add(line.Substring(1, line.Length - 1)); //here
}
else if (line.StartsWith("-"))
{
vars.hints[counter].Add(line.Substring(1, line.Length - 1)); //another here
}
else if (line == "#end")
{
counter++;
}
}
}
I looked online for some references but didn't have too much luck. Hopefully it's just some simple thing I'm overlooking, but in my code I'm looping through the participant list and storing the queried results into the array. As you can tell, my foreach statement will just add the last element of the array since the first one is replaced.
How can I just add the value to the next array index. So, if there are [2] in the array, how can I make sure that this.physEntityPhysicalLeftEntityIDs contains [2] instead of just always [1]? If I need to clarify, let me know.
if (leftParticipants.Length >= 0) // Check to see if LeftParticipants exists
{
for (int c = 0; c < leftParticipants.Length; c++)
{
var l_entityIDs =
from BioList in o_data.Descendants(bp + "physicalEntityParticipant")
where BioList.Attribute(rdf + "ID").Value == leftParticipants[c].TrimStart('#')
select new
{
o_entityIDs = BioList.Elements(bp + "PHYSICAL-ENTITY")
.Select(entityID => entityID.Attribute(rdf + "resource").Value).ToArray()
};
foreach (var entity in l_entityIDs)
{
this.physEntityPhysicalLeftEntityIDs = entity.o_entityIDs; // Set SmallMolecules from Left
}
}
}
If physEntityPhysicalLeftEntityIDs is an array, you'll need to initialize an index variable and increment it each time through the foreach loop:
int destIndex = 0;
foreach (var entity in l_entityIDs)
{
this.physEntityPhysicalLeftEntityIDs[destIndex] = entity.o_entityIDs; // Set SmallMolecules from Left
++destIndex;
}
That assumes that you've allocated enough space in the array. If there are more items than will fit in the array, you're going to get an index out of bounds error.
To make sure there's enough space in the array, you can allocate it before the loop above:
this.physEntityPhysicalLeftEntityIds = new int[l_entityIDs.Count()];
Replace int in that line with the proper type (you didn't say what type is being stored in the array).
Well if you want to treat it like an array/list, all you have to do is
l_enityIDs.ToList()
and then .Add(new {o_entityIDs = foo})
If you want to add it to the IEnumerable, that requires an extension method that returns everything in the source enumberable, and a yield statement adding on your next value.