To make a linq with a multiple foreach - c#

I have several foreach chained.
I would like to know if it is possible to do a linq synthesis of these foreach.
foreach(var item in parameter)
{
foreach (var worksheets in item.Item6.Worksheets)
{
var worksheetName = worksheets.Value.Name;
foreach (var dynamicRange in worksheets.Value.DynamicRanges)
{
var dynamicRangeRowStartIndex = dynamicRange.RowStartIndex;
var dynamicRangeColumnStartIndex = dynamicRange.ColumnStartIndex;
foreach (var node in dynamicRange.Nodes)
{
var nodeDirection = node.Direction;
foreach (var rule in node.Rules)
{
reportWorkbook.Worksheets.Values.First(c => c.Name == worksheetName).DynamicRanges.First(c => c.RowStartIndex == dynamicRangeRowStartIndex && c.ColumnStartIndex == dynamicRangeColumnStartIndex)
.NodeByDirection(nodeDirection).Rules[ruleCount].DefinitionRule.ContextItem = item.Item6.Worksheets.Values.First(c => c.Name == worksheetName).DynamicRanges.First(c => c.RowStartIndex == dynamicRangeRowStartIndex && c.ColumnStartIndex == dynamicRangeColumnStartIndex)
.NodeByDirection(nodeDirection).Rules[ruleCount].DefinitionRule.ContextItem;
ruleCount++;
}
ruleCount = 0;
}
}
}
}
Do you have any idea how to do this?
Thank you

Related

Change loop to Linq C#

One of my function in C# required me to filter some value.So, I try it by using a lot of loop in it. It works but doesn't look like effecient.Any idea on how to convert code below to LinQ?
Any help is appreciated.
var object1 = JsonConvert.DeserializeObject<List<string>>(object1json);
foreach (var item1 in table1)
{
if (item1.Code == InputCode)
{
for (int i = 0; i < object1.Count(); i++)
{
tempData temp = new tempData();
foreach (var item2 in item1.List)
{
if (item2.Code == object1[i])
{
temp.Code = item2.Code;
temp.Description = item2.Description;
}
}
if(temp.Code != null || temp.Description != null)
final.Add(temp);
}
}
}
If you want your code to be more efficient, as pointed out in the comments, converting it to Linq isn't really going to help. It's still the same logic, just written in a different way. If you're going for readability, it can be improved with just a few changes:
foreach (var item1 in table1.Where(i => i.Code == InputCode))
{
foreach (var code in object)
{
// This could be SingleOrDefault, I don't know if you have duplicates in the list or not
var item2 = item1.List.LastOrDefault(i => i.Code == code);
if(item2 != null)
{
final.Add(new tempData
{
Code = item2.Code,
Description = item2.Description,
});
}
}
}
If you convert the whole thing to Linq:
var final = table1.Where(i => i.Code == InputCode)
.SelectMany(item1 => object.Select(code => item1.List.LastOrDefault(i => i.Code == code))
.Where(item2 => item2 != null)
.Select(item2 => new tempData
{
Code = item2.Code,
Description = item2.Description,
})
.ToList();
Personally, I prefer the first option, as it's a bit easier to read.
I guess what you post is sample code instead of actual code otherwise it would be better to avoid keyword like object in C#. Anyway,
var final = table1.Where(item1 => item1.Code == InputCode)
.SelectMany(item1 => item1.List)
.Where(item2 => #object.Contains(item2.Code))
.Where(temp => temp.Code != null || temp.Description != null)
.Select(item2 => new tempData()
{
Code = item2.Code,
Description = item2.Description
});

Tidying up lambda expressions

The following code gives me the results I need, but can anyone suggest how to write it better? I'm sure there's a more efficient way to do it.
Thanks.
private bool IsLocation(Guid _vID, Guid OrganisationId)
{
var vehicle = _vehilceRepository.GetSingle(c => c.vehicleId == _vID);
var clients = _clientRepository.GetList(c => c.OrganisationID == OrganisationId);
foreach (var client in clients)
{
var locations = _LocationRepository.GetList(c => c.ClientID == client.ClientID);
if (locations.Count > 0)
{
foreach (var location in locations)
{
if (location.LocationId == vehicle.LocationID)
{
return true;
}
}
}
}
return false;
}
var vehicle = _vehilceRepository.GetSingle(c => c.vehicleId == _vID);
var clients = _clientRepository.GetList(c => c.OrganisationID == OrganisationId);
return clients.SelectMany(client => _LocationRepository.GetList(
c => c.ClientID == client.ClientID))
.Any(location => location.LocationId == vehicle.LocationID);
?

C# Code Optimization GroupBy

I have a couple of problems with my below code.
var groupedItems = inputFiles.GroupBy(q => q.Name.ToLower().Split('_').ElementAt(2));
string currentNo = ////value retreived from someMethod;
if (string.IsNullOrEmpty(currentNo))
{
if (groupedItems.Count() > 1)
{
foreach (var group in groupedItems)
{
foreach (var groupedItem in group)
{
ErrorFile(groupedItem);
}
}
}
else if (groupedItems.Count() == 1)
{
ProcessFile();
}
}
else
{
foreach (var group in groupedItems.Where(x => x.Key != currentNo))
{
foreach (var groupedItem in group)
{
ErrorFile(groupedItem);
}
}
}
There is repetitive code with nested foreach loops. I am looking at possibility of optimization
How do I handle when Split and ElementAt(2) return errors. I still need to call ErrorFile() method even if I am unable to Split by _.
Hard to understand what your code is really doing without more context, but this should be about right:
static void SomeMethod(IEnumerable<File> inputFiles)
{
var groupedItems = inputFiles.GroupBy
(f => splitAndFindElement(f.Name, '_', 2, string.Empty));
string currentNo = //whatever;
if (string.IsNullOrEmpty(currentNo))
{
if (groupedItems.Count() > 1)
{
foreach (var item in groupedItems.SelectMany(g => g))
{
ErrorFile(item);
}
}
else if (groupedItems.Count() == 1)
{
ProcessFile();
}
}
else
{
foreach (var item in groupedItems.Where(g => g.Key != currentNo).SelectMany(g => g))
{
ErrorFile(item);
}
}
}
And the helper method:
static string splitAndFindElement(string input, char splitter, int index, string resultOnFail)
{
var succesful = false;
string[] words = null;
if (input != null)
{
words = input.Split(splitter);
succesful = words.Length > index;
}
return succesful ? words[index] : resultOnFail;
}
The trick here is to group files with key "" if they can't be split. This will ensure that they will be processed with ErrorFile either becuase there is more than one grouping or because the key does not equal currentNo. I'm assuming here that Name can't end in "_".
Also, SelectMany is used to flatten enumerables of enumerables and avoid nested loops.
We can optimize repeated loops as following, and to handle error use try catch
var groupedItems;
try
{
groupedItems= inputFiles.GroupBy(q => q.Name.ToLower().Split('_').ElementAt(2));
string currentNo = ////value retreived from someMethod;
if (string.IsNullOrEmpty(currentNo) && groupedItems.Count() == 1)
{
ProcessFile();
}
else
{
foreach (var group in groupedItems.Where(x => string.IsNullOrEmpty(currentNo) || x.Key != currentNo))
{
foreach (var groupedItem in group)
{
ErrorFile(groupedItem);
}
}
}
}
catch
{
ErrorFile(groupedItem);
}

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.

Entity many to many check if relation exists

I have two tables: Items and Colors. They have a many to many relation. In a CheckBoxList that displays colors, I want to check those that are associated to the item shown.
using (var db = new ProwebModel.Entities())
{
var colors = db.Colors;
foreach (ListItem color in ((CheckBoxList)(fv.FindControl("cblColors"))).Items)
{
var itemId = Convert.ToInt32(Request.QueryString["id"]);
var colorNumber = Convert.ToInt32(color.Value);
color.Selected = colors.Where(t => t.ColorNumber == colorNumber).First().Items.Where(t => t.ItemId == itemId).Count() > 0;
}
}
This works fine, but I was wondering about this line :
color.Selected = colors.Where(t => t.ColorNumber == colorNumber).First().Items.Where(t => t.ItemId == itemId).Count() > 0;
Is there any better way to check if the association exist?
Thank you!
EDIT
I chaged my code to something better.. I think. Is there still a better way to do this?
using (var db = new ProwebModel.Entities())
{
var itemId = Convert.ToInt32(Request.QueryString["id"]);
var ItemColors = db.Items.First(t => t.ItemId == itemId).Colors.ToList();
foreach (ListItem color in ((CheckBoxList)(fv.FindControl("cblColors"))).Items)
{
var colorNumber = Convert.ToInt32(color.Value);
color.Selected = ItemColors.Where(t => t.ColorNumber == colorNumber).Count() > 0;
}
}
Many thanks!
Code update
using (var db = new ProwebModel.Entities())
{
var itemId = Convert.ToInt32(Request.QueryString["id"]);
var ItemColors = db.Items.First(t => t.ItemId == itemId).Colors.ToList();
foreach (ListItem color in ((CheckBoxList)(fv.FindControl("cblColors"))).Items)
{
var colorNumber = Convert.ToInt32(color.Value);
color.Selected = ItemColors.Any(t => t.ColorNumber == colorNumber);
}
}
The line could at least be rewritten as :
color.Selected = colors.First(t => t.ColorNumber == colorNumber).Items.Any(t => t.ItemId == itemId);

Categories

Resources