Execute foreach loop fully, though if statement get executed in loop - c#

I am using foreach loop, now what I want is this loop should run for each elements in that loop count.
Once that is finished then it should return to the function, here in this loop I have also use if statement.
But problem is when first time if statement is executing it is returning to that function without finishing whole foreach loop count.
But instead of that, it should run foreach loop fully and then return with that messages.
Below is code :
foreach (var field in fields.OrderBy(x => x.Sequence))
{
if (!header.Any(x => x.Sequence == field.Sequence && x.Name == field.Name))
{
var colName = header.Where(x => x.Sequence == field.Sequence).Select(x => x.ExcelColName).FirstOrDefault();
var newheaderName = header.Where(x => x.Sequence == field.Sequence).Select(x => x.Name).FirstOrDefault();
message = string.Format("In cell {0}1, column '{1}' was expected but '{2}' was there. The Excel data will NOT be imported.", colName, field.Name, newheaderName);
messageList.Add(message); // Here after adding all message in list, then it should return to calling function
} else
{
}
return null;
}

Put the return messageList at the end of the method.
Sidenote: you can improve performance much: don't filter on Sequence three times per iteration. Store the result of header.Where(x => x.Sequence == field.Sequence) at the beginning of the foreach in a list-variable. Then check if it contains items:
foreach (var field in fields.OrderBy(x => x.Sequence))
{
var seqHeaders = header.Where(x => x.Sequence == field.Sequence).ToList();
var matchingHeader = seqHeaders.FirstOrDefault(h => h.Name == field.Name);
if(!seqHeaders.Any())
{
// you didn't handle this case
messageList.Add($"Sequence not found '{field.Sequence}'. The Excel data will NOT be imported.");
}
else if (matchingHeader == null)
{
string colName = seqHeaders[0].ExcelColName;
string newHeaderName = seqHeaders[0].Name;
messageList.Add($"In cell {colName} column '{field.Name}' was expected but '{newHeaderName}' was there. The Excel data will NOT be imported.");
}
else
{
// use matchingHeader ...
}
}
// rest of method here ...
return messageList; // don't return null but an empty list if there were no errrors

Your return is in your foreach loop. Bring it out of the scope of the foreach.

Let's say you call your function like this.
CallMyFunction();
...
If you don't need anything to be returned from this function then use void like this.
public void CallMyFunction()
{
foreach (var field in fields.OrderBy(x => x.Sequence))
{
if (!header.Any(x => x.Sequence == field.Sequence && x.Name == field.Name))
{
var colName = header.Where(x => x.Sequence == field.Sequence).Select(x => x.ExcelColName).FirstOrDefault();
var newheaderName = header.Where(x => x.Sequence == field.Sequence).Select(x => x.Name).FirstOrDefault();
message = string.Format("In cell {0}1, column '{1}' was expected but '{2}' was there. The Excel data will NOT be imported.", colName, field.Name, newheaderName);
messageList.Add(message); // Here after adding all message in list, then it should return to calling function
} else
{
} // Remove entirely the return.
}
That way your loop will fully run.

Related

How do you call a function to an Linq List query that uses the exist function

I have this method with a linq statement below. I'm not a fan of multiple if statement and I'm trying to find what is the best way to not have these if statement and have a private method.
My field values is being set as such:
var fieldValues = await GetFields // then it's being passed to my method.
public static AppraisalContactBorrower BuildCoBorrower(List<LoanFieldValue> fieldValues) {
var coborrower = new AppraisalContactBorrower();
if (fieldValues.Exists(f => f.FieldId == "CX.OS.AO.COBORRNAME")) {
coborrower.Name = fieldValues.First(v => v.FieldId == "CX.OS.AO.COBORRNAME").Value;
}
if (fieldValues.Exists(f => f.FieldId == "CX.OS.AO.BORRCONTACTZIP")) {
borrower.Zip = fieldValues.First(v => v.FieldId == "CX.OS.AO.BORRCONTACTZIP").Value;
}
if (fieldValues.Exists(f => f.FieldId == "CX.OS.AO.BORRCONTACTZIP")) {
borrower.Zip = fieldValues.First(v => v.FieldId == "CX.OS.AO.BORRCONTACTZIP").Value;
}
What I'm trying to do is instead of this:
coborrower.Name = fieldValues.First(v => v.FieldId == "CX.OS.AO.COBORRNAME").Value;
Is having something similar to this.
if (fieldValues.Exists(f => f.FieldId == "CX.OS.AO.BORRCONTACTZIP")) {
coborrower.Name = SETVALUE("CX.OS.AO.BORRCONTACTZIP")}
First, try using Enumerable.ToDictionary to have the field values grouped by FieldId, then use IDictionary.TryGetValue to get the existing values:
public static AppraisalContactBorrower BuildCoBorrower(List<LoanFieldValue> fieldValues) {
var groupedFieldValues = fieldValues.ToDictionary(f => f.FieldId)
var coborrower = new AppraisalContactBorrower();
if (groupedFieldValues.TryGetValue("CX.OS.AO.COBORRNAME", out var name)) {
coborrower.Name = name.Value;
}
if (groupedFieldValues.TryGetValue("CX.OS.AO.BORRCONTACTZIP", out var zip)) {
borrower.Zip = zip.Value;
}
}
Using Dictionary makes it faster to check the appropriate field existence as it is O(1) and with TryGetValue you combine two operations into one (existence check + obtaining the value).
Your two last statements are almost identitical. The equivalent of :
if (groupedFieldValues.TryGetValue("CX.OS.AO.COBORRNAME", out var name)) {
coborrower.Name = name.Value;
}
is:
coborrower.Name = fieldValues.FirstOrDefault(v => v.FieldId == "CX.OS.AO.COBORRNAME")
?? coborrower.Name;
In the original code, coborrower.Name is not updated if the field doesn't exist in the list.

What Do Multiple Return Statements in a Linq.Select() Do?

I'm seeing a lot of select statements with return statements in them and Im confused of what is going on when an object is being returned from within a select statement. Can someone please explain?
var results = swimEntries
.Select(se =>
{
if (se.Tag == "DM+" || se.Tag == "DM-")
{
var modelEntry =
modelEntries.Find(e => e.Tag == se.Tag);
return modelEntry;
}
return se;
})
.ToList();
What you see here is a Statement lambda. The Select() will call for each item the code in it's body. When the se.Tag meets some criteria, it will search for an object in the modelEntries.
You could write this statement also as:
var results = new List<ModelEntry>(); // <-- i don't know the exact type.. (wild guess)
foreach(var se in swimEntries)
{
if (se.Tag == "DM+" || se.Tag == "DM-")
{
var modelEntry = modelEntries.Find(e => e.Tag == se.Tag);
results.Add(modelEntry);
}
else
results.Add(se);
}
or if you want to keep the Select statement, you could store the body into a separate function:
private ModelEntry SearchForSomething(ModelEntry se)
{
if (se.Tag == "DM+" || se.Tag == "DM-")
{
var modelEntry = modelEntries.Find(e => e.Tag == se.Tag);
return modelEntry;
}
return se;
}
var results = swimEntries.Select(SearchForSomething).ToList();

Access item in sequence that was skipped using LINQ's .Skip()

foreach(var item in items.Where(x => x.SomeCondition == true).Skip(1))
{
item.OneThing = true;
item.AnotherThing = true;
}
For the item that was skipped using .Skip(1), I also need to set .AnotherThing to true. I can iterate everything without .Skip(1) and set .AnotherThing to true, then iterate everything with .Skip(1) and set .OneThing to true. Is there a more elegant way to do this, rather than looping through the collection twice?
Edit: What if there was a .YetAnotherThing property, which needed to be set on the item that was skipped using .Skip(1)?
Well it sounds like you don't want to use Skip in this case. Just use a local variable to remember whether this is the first iteration or not.
bool firstItem = true;
foreach(var item in items.Where(x => x.SomeCondition))
{
item.AnotherThing = true;
if (!firstItem)
{
item.OneThing = true;
}
firstItem = false;
}
Don't use Skip(1) in your foreach loop then. You can also do a Select to get the index as the second parameter.
foreach (var item in items.Where(x => x.SomeCondition)
.Select((x, i) => new { item = x, index = i })
{
// If you have a lot to do:
if (item.index != 0)
{
item.item.YetAnotherThing = 15;
item.item.OneThing = true;
}
// If you have a simple boolean
item.item.OneThing = item.index != 0;
// Something that will always happen.
item.item.AnotherThing = true;
}
Granted, in actual code, please pick better variable names than what would create item.item.
How about
var newItems = items.Where(x => x.SomeCondition == true).ToList();
if(newItems.Count != 0)
{
newItems.ForEach(i => i.AnotherThing = true);
newItems.FirstOrDefault().OneThing = true;
}

Can I include a check for null details inside a forEach?

I have this code:
foreach (var result in results)
{
if (result.definition != null)
{
WordForm wordForm = db.WordForms
.Where(w => w.Definition == result.definition)
.FirstOrDefault();
if (wordForm == null)
{
wordForm = addWordForm(result, word);
}
addWordFormExamples(result, word, wordForm);
addWordFormSynonyms(result, word, wordForm);
db.SaveChanges();
}
}
Is there a way I could optimize this using a .forEach and also by adding in a check to see if the definition is null as part of the actual .forEach ? I would like to clean up this code and so trying what I can to further simplify it.
Note that I already moved this to a private method:
private void processWordForm(Word word, Result result)
{
WordForm wordForm = db.WordForms
.Where(w => w.Definition == result.definition)
.FirstOrDefault();
if (wordForm == null)
{
wordForm = addWordForm(result, word);
}
addWordFormExamples(result, word, wordForm);
addWordFormSynonyms(result, word, wordForm);
db.SaveChanges();
}
So now I just need a more tidy way to call this method if there is a way.
You're getting all the results before doing the foreach loop and inside the loop you check if every single one contains a definition which is not null.That means that you are actually only interested in results which contain a definition.
You can re-factor your code slightly by modifying the query which sets the results object to only contain results with a definition.This will remove the need for having the null check inside the foreach loop.
Something like this:
var results = sourceOfData.Where(i => e.definition != null).ToList();
foreach (var result in results)
{
WordForm wordForm = db.WordForms
.Where(w => w.Definition == result.definition)
.FirstOrDefault();
if (wordForm == null)
{
wordForm = addWordForm(result, word);
}
addWordFormExamples(result, word, wordForm);
addWordFormSynonyms(result, word, wordForm);
db.SaveChanges();
}

Error while removing item from collection

Getting error Collection was modified; enumeration operation may not execute.
var toUpdateItm = MC_CRM_T001A.ItemDetails
.Where(X => X.CatNo == SelectedCRM_T001A.CatNo);
foreach (var itm in toUpdateItm)
{
int x = MC_CRM_T001A.PartDetails.IndexOf(MC_CRM_T001A.PartDetails
.Where(X => X.cat_item_id == itm.id)
.FirstOrDefault()
);
if (x >= 0 && x!=null)
{
MC_CRM_T001A.PartDetails.RemoveAt(x);
}
}
foreach (var itm in toUpdateItm)
{
if (itm.CatNo == SelectedCRM_T001A.CatNo)
{
MC_CRM_T001A.ItemDetails.Remove(itm);
}
}
You can't modify the list you're looping over. Change for foreach calls to foreach (var itm in toUpdateItem.ToList()), which will create a copy of the list, instead.
Also, you can express this code more cleanly without all the IndexOf stuff:
var toUpdateItm = MC_CRM_T001A.ItemDetails.Where(X => X.CatNo == SelectedCRM_T001A.CatNo).ToList();
foreach (var itm in toUpdateItm.ToList())
{
var item = MC_CRM_T001A.PartDetails.FirstOrDefault(X => X.cat_item_id == itm.id);
if (item != null) { MC_CRM_T001A.PartDetails.Remove(item); }
if (itm.CatNo == SelectedCRM_T001A.CatNo) { MC_CRM_T001A.ItemDetails.Remove(itm);
}
You don't need two loops either.

Categories

Resources