This question already has answers here:
How to remove elements from a generic list while iterating over it?
(28 answers)
Closed 3 years ago.
Is there any way I can search List<T> and remove empty items?
ObservableCollection ListOfTnAGroupAccs <Model>
foreach (var item in ListOfTnAGroupAccs)
{
if(item.Prefix == "" && item.ReportingGrp == "" && item.AccMngInitials == "" && item.Description == "")
{
ListOfTnAGroupAccs.Remove(item);
continue;
}
}
it gives me "Collection was modified; enumeration operation may not execute"
I can use this
var nList = ListOfTnAGroupAccs.Where(l => l.Prefix != "" && l.ReportingGrp != "" && l.AccMngInitials != "" && l.Description != "").ToList();
But my curiosity is there any better way to do it?
You cannot remove items while iterationg them, and thus the exception. One way to do it is to do a regular backwards for loop:
for(int i = ListOfTnAGroupAccs.Length -1; i >= 0; --i)
{
var item = ListOfTnAGroupAccs[i];
if(item.Prefix == "" && item.ReportingGrp == "" && item.AccMngInitials == "" && item.Description == "")
{
ListOfTnAGroupAccs.Remove(item);
continue;
}
}
The way it occurs is that you are iterating over collection which you want to modify in a loop, which may break iteration.
The best approach is to loop backwards:
for(int i = ListOfTnAGroupAccs.Length - 1; i >= 0; i--)
if(item.Prefix == "" && item.ReportingGrp == "" && item.AccMngInitials == "" && item.Description == "")
ListOfTnAGroupAccs.RemoveAt(i);
Use a for-loop instead of foreach.
for (int i = ListOfTnAGroupAccs.Count-1; i>=0; i--)
{
if(ListOfTnAGroupAccs[i].Prefix == "" && ListOfTnAGroupAccs[i].ReportingGrp == "" && ListOfTnAGroupAccs[i].AccMngInitials == "" && ListOfTnAGroupAccs[i].Description == "")
{
ListOfTnAGroupAccs.RemoveAt(i);
continue;
}
}
We are going through the list in reverse order because we remove items. This way we prevent an IndexOutOfRangeException.
Related
I have function which calculates quantity .Its working fine but some due to null values in field it does not return anything . these field can be null .i want to calculate only where both fields are not null. i think i need to use foreach but i dont know the way how can i use it here .
Help appreciated
private double Get_Quantity()
{
try
{
double sum = 0;
sum = (double)(from s in ManagerClass.oSqlData.table
where s.Demand.Order.Order_ID == Order_ID
where s.Demand.Order.Order_Date >= ManagerClass.startDate && s.Demand.Order.Order_Date <= ManagerClass.EndDate
select s.ValueA - s.ValueB ).Sum();
return sum;
}
catch
{
return 0;
}
}
Try like this;
sum = (double)(from s in ManagerClass.oSqlData.table
where (s.Demand != null && s.Demand.Order != null && s.Demand.Order.Order_ID == Order_ID)
&& (s.Demand != null && s.Demand.Order != null && s.Demand.Order.Order_Date >= ManagerClass.startDate && s.Demand.Order.Order_Date <= ManagerClass.EndDate)
&& s.ValueA != null
&& s.ValueB != null
select s.ValueA - s.ValueB).DefaultIfEmpty(0).Sum();
I have a ConcurrentDictionary of Attributes for products. These attributes have the product ID and values for the names of the attribute and any options the attribute has. I have this ConcurrentDictionary because I have threads that are created to handle each attribute in the dictionary by attribute name.
if (knownAttribute.AttributeType.Value.Equals("Product Specification"))
{
Console.WriteLine("Started a thread for: " + knownAttribute.AttributeTypeId + ", " + knownAttribute.Value);
while (true)
{
/* if (AS400SpecificationAttributes.IsEmpty && knownSpecificationBag.IsEmpty && gatherRowsTasks.All(x => x.IsCompleted))
break;*/
AS400SpecificationAttribute AS400SpecificationAttributeWork = null;
AS400SpecificationAttributeWork = knownSpecificationBag.Keys.FirstOrDefault(x => x.AttributeName == knownAttribute.Value);
if (AS400SpecificationAttributeWork != null)
{
var product = ctx.Products.FirstOrDefault(x => x.ProductNumber == AS400SpecificationAttributeWork.ProductNumber);
if (product == null)
continue;
var productAttribute = new ProductAttribute();
productAttribute.Attribute = knownAttribute;
if (AS400SpecificationAttributeWork.AttributeValue != null)
{
var knownAttributeOption = ctx.AttributeOptions.FirstOrDefault(x => x.Attribute.Equals(knownAttribute) && x.Value.Equals(AS400SpecificationAttributeWork.AttributeValue));
if (knownAttributeOption == null)
{
knownAttributeOption = new AttributeOption();
knownAttributeOption.Value = AS400SpecificationAttributeWork.AttributeValue;
knownAttributeOption.Attribute = knownAttribute;
ctx.AttributeOptions.InsertOnSubmit(knownAttributeOption);
ctx.SubmitChanges();
}
productAttribute.AttributeOption = knownAttributeOption;
productAttribute.AttributeOptionId = knownAttributeOption.Id;
}
product.ProductAttributes.Add(productAttribute);
ctx.SubmitChanges();
string tmpstr = null;
if (!knownSpecificationBag.TryRemove(AS400SpecificationAttributeWork, out tmpstr))
Thread.Sleep(50);
}
else
{
if (tryCounter < 5)
{
tryCounter++;
Thread.Sleep(1000);
Console.WriteLine("Thread waiting for work: Product Specification:" + knownAttribute.Value);
continue;
}
else
{
int outVal;
threadTracker.TryRemove("Product Specification:" + knownAttribute.Value, out outVal);
Console.WriteLine("Closing Thread: Product Specification:" + knownAttribute.Value);
break;
}
}
Thread.Sleep(50);
}
It seems like the following Attribute element refuses to be removed.
I don't understand why. If i put it in a while(!dic.tryRemove(ele)) it will forever be stuck and never move from there.
There may be an error somewhere within the thread but I have no idea why.
This statement
if (!knownSpecificationBag.TryRemove(AS400SpecificationAttributeWork, out tmpstr))
will always return true or false. It won't block. That's the behavior of ConcurrentDictionary. It will return false if the key is not in the dictionary.
If you're looping while that method returns false and it's stuck, that means that the item isn't in the dictionary when the loop begins. Either it either was never in the dictionary or that another thread already removed it.
Is your intention to loop until the item is not in the dictionary?
You could try this:
if (!knownSpecificationBag.TryRemove(AS400SpecificationAttributeWork, out tmpstr)
&& !knownSpecificationBag.ContainsKey(AS400SpecificationAttributeWork))
Implement proper equals and gethashcode when using TryRemove
public override int GetHashCode()
{
return new { this.name, this.value, this.group, this.productNumber }.GetHashCode();
}
public bool Equals(AS400SpecificationAttribute other)
{
if (other == null)
return false;
return (this.ProductNumber.Equals(other.productNumber) && ((this.group != null && this.group.Equals(other.AttributeGroup)) || (this.group == null && other.AttributeGroup == null)) && ((this.name!= null && this.name.Equals(other.AttributeName)) || (this.name == null && other.AttributeName == null)) && ((this.value != null && this.value.ToUpper().Equals(other.AttributeValue.ToUpper())) || (this.value == null && other.AttributeValue == null)));
}
I have an IF statement that is supposed to make sure the TextBox1.Text and TextBox2.Text do not match or are not blank. If they don't match or are not blank then it is supposed to assign the text in the boxes to two string variable. What I can't figure out is why when I leave the two textboxes blank the true statement still fires.
if ((tbStartBreak2.Text != tbEndBreak2.Text) || (tbStartBreak2.Text == "" && tbEndBreak2.Text == ""))
{
sb2 = tbStartBreak2.Text;
se2 = tbStartBreak2.Text;
}
There are two conditions in your if statement:
if ((tbStartBreak2.Text != tbEndBreak2.Text) || (tbStartBreak2.Text == "" && tbEndBreak2.Text == ""))
The first one checks to make sure they don't match (so, good). The second checks to make sure that they are blank (so, bad). You want this:
if ((tbStartBreak2.Text != tbEndBreak2.Text) || (tbStartBreak2.Text != "" && tbEndBreak2.Text != ""))
Also, what are you trying to do? The second condition is the only one you need if you really want them not to match OR not be blank - because the only time this will be false is if they are both blank.
You wrote "OR textbox are blank", you need "OR textbox are not blank"
if ((tbStartBreak2.Text != tbEndBreak2.Text) || (tbStartBreak2.Text != "" && tbEndBreak2.Text != ""))
{
sb2 = tbStartBreak2.Text;
se2 = tbStartBreak2.Text;
}
As a side note, I'd replace "" with string.Empty for readability.
if ((tbStartBreak2.Text != tbEndBreak2.Text) || (tbStartBreak2.Text != string.Empty && tbEndBreak2.Text != string.Empty))
{
sb2 = tbStartBreak2.Text;
se2 = tbStartBreak2.Text;
}
And for even more readability, you can extract these big conditions
if (TextboxesDoNotMatch() || TextboxesAreNotEmpty())
{
sb2 = tbStartBreak2.Text;
se2 = tbStartBreak2.Text;
}
private bool TextboxesDoNotMatch()
{
return tbStartBreak2.Text != tbEndBreak2.Text;
}
private bool TextboxesAreNotEmpty()
{
return tbStartBreak2.Text != string.Empty && tbEndBreak2.Text != string.Empty;
}
If you want it to return that they are NOT blank then you need to do this
(tbStartBreak2.Text != "" && tbEndBreak2.Text != "")
you have an OR between both conditions so when both are empty the second part will be true regardless the first part
(tbStartBreak2.Text == "" && tbEndBreak2.Text == "")
I have the following code on an asp.net button click
if(str == ipaddr1 || ipaddr2 || ipaddr3 || ipaddr4 || ipaddr5 || ipaddr6 || ipaddr7)
// do this
else
//cancel click event
How can I optimize this piece of code?
Update: Apologies everyone! I did not mean to compare it with the literal string ipaddr. I mean to compare it to the value ipaddr1, ipaddr2 holds and so on
replace with:
Regex.IsMatch(str, "^ipaddr[1-7]$")
Optimised for readability not necessarily performance.
HashSet<T> is the best container to check containing:
var ips = new HashSet<string> { "ip1", "ip2", "ip3", "ip4", "ip5" };
if (ips.Contains(input))
{
// do stuff
}
For any type:
var ips = new HashSet<IPHostEntry> { ip1, ip2, ip3, ip4, ip5 };
if (ips.Contains(input))
{
// do stuff
}
Was:
if(str = qry.StartsWith("23.55") || str = qry.StartsWith("xuz") || str = qry.StartsWith("i3") || str = qry.StartsWith("i444") || str = qry.StartsWith("ki5") || str = qry.StartsWith("65fr6")) // do this else // do this
Become:
var arr = new[] { "23.55", "xuz", "i3", "i444", "ki5", "65fr6") };
if (arr.Any(str => input.StartsWith(str, StringComparison.Ordinal))
{
// do stuff
}
StringComparison.Ordinal or StringComparison.OrdinalIgnoreCase are very important for performance.
What about
if(str.Substring(0,6) == "ipaddr" && str[6] >= '1' && str[6] <= '7')
For your information, your original code does not even compile. This
if(str == "ipaddr1" || "ipaddr2" || "ipaddr3" || "ipaddr4" || "ipaddr5" || "ipaddr6" || "ipaddr7")
Needs to be replaced with this to compile
if(str == "ipaddr1" || str == "ipaddr2" || str == "ipaddr3" || str == "ipaddr4" || str == "ipaddr5" || str == "ipaddr6" || str == "ipaddr7")
So the original code is actually even more tedious than you thought.
UPDATE
According to your updated question, the best option is to put your string variables into a List<string> called, for example ipaddr. Then to see if the string str is included, simply do this:
if( ipaddr.Contains( str ) )
{
//contained in the list
}
I would do something like:
str.Length == 7 && str.StartsWith("ipaddr") && str[6] > '0' && str[6] < '8'
Edit:
After your update, I would do something like:
string[] validStrings = { ipaddr1, ipaddr2, ... };
bool isStrValid = validStrings.Contains(str);
For better performance, consider using a HashSet<string> instead of an array, especially if the list of valid strings doesn't change.
Both more readable, and more performant would be:
switch(str)
{
case "ipaddr1":
case "ipaddr2":
case "ipaddr3":
case "ipaddr4":
case "ipaddr5":
case "ipaddr6":
case "ipaddr7":
//do something
break;
default:
//do something else
break;
}
(although, admittedly massively verbose...)
I would do a
List<string> variables = new List<string> { "ip1","ip2","ip3","ip4","ip5" };
if (variables.Contains(inputstring))
...
I am still in the process of learning Asp.Net. I have a question . I was using an if condition in which i was checking dataset values. It is throwing me an exception whenever it is checking the condition as the dataset has not got any value. How to overcome this.
Code for this is here:
DataSet ds = merchant.getIsactiveIsconfirmedforcancelaccount(merchantID);
if (_merchant.PackageID == (int)CommonHelper.Package.Free && _merchant.AccountStatus.Contains("Awaiting"))
{
spnMerchantActiveStatus.InnerHtml = ApplicationData.MSG_AWAITING_CONFIRMATION;
}
***else if ((ds.Tables[0].Rows[0]["IsConfirmed"]).ToString() == "True" && (ds.Tables[0].Rows[0]["Active"]).ToString() == "N")***
{
_merchant.AccountStatus = "Cancelled";
spnMerchantActiveStatus.InnerHtml = _merchant.AccountStatus;
}
else if(_merchant.PackageID != (int)CommonHelper.Package.Free && ds1.Tables[0].Rows.Count == 0 && (ds2.Tables[0].Rows[0]["ConfirmationSrc"]).ToString() == "Admin")
{
_merchant.AccountStatus = "Free Trial";
spnMerchantActiveStatus.InnerHtml = _merchant.AccountStatus;
}
else
spnMerchantActiveStatus.InnerHtml = _merchant.AccountStatus;
}
The exception here is "There is no row at position 0."
Seems like you do not have any rows in your tables[0]. You can add condition to check is rows > 0 and then continue with other conditions in the IF.
You are assuming you have rows in your DataSet.
Instead of
if ((ds.Tables[0].Rows[0]["IsConfirmed"]).ToString() == "True" &&
(ds.Tables[0].Rows[0]["Active"]).ToString() == "N")
you should do something like
if ((ds.Tables[0].Rows.Count() > 0) &&
(ds.Tables[0].Rows[0]["IsConfirmed"]).ToString() == "True" &&
(ds.Tables[0].Rows[0]["Active"]).ToString() == "N")
But you really need to do fuller error checking than just that one condition affectin you right now.
EDIT: If it's not obvious why the above works, read up on short-circuiting of logical operators: http://msdn.microsoft.com/en-us/library/2a723cdk(VS.71).aspx
Try changing your else statement :
else if (
(ds.Tables[0].Rows[0]["IsConfirmed"]).ToString() == "True" &&
(ds.Tables[0].Rows[0]["Active"]).ToString() == "N")
{
_merchant.AccountStatus = "Cancelled"; spnMerchantActiveStatus.InnerHtml = _merchant.AccountStatus;
}
To
if ((null != ds.Tables[0]) && ((ds.Tables[0].Rows[0]["IsConfirmed"]).ToString() == "True") && ((ds.Tables[0].Rows[0]["Active"]).ToString() == "N"))
So that you check that the data set is not null before you check conditions on it.
or (as other posters say) check that you actually have rows in the dataset.
ds.Tables[0].Rows.Count() != 0