LINQ query to update property of a list - c#

I am trying to convert the following code to linq:
for (int i = 0; i < List.Count;i++ )
{
List[i].IsActive = false;
if(List[i].TestList != null)
{
for(int j = 0;j<List[i].TestList.Count;j++)
{
List[i].TestList[j].IsActive = false;
}
}
}
I tried the following query :
(from s in List select s).ToList().ForEach((s) =>
{
s.IsActive = false;
(from t in s.TestList where t != null select t).ToList().ForEach((t) =>
{
t.IsActive = false;
});
});
But i get an error when TestList is null in the list. I am not sure what I am doing wrong here.

If your original(no LINQ) code is worked.
Then you missed one line, which check for null of TestList before iterating items
(from s in List select s).ToList().ForEach((s) =>
{
s.IsActive = false;
if(s.TestList != null) //This check of TestList was missing
(from t in s.TestList where t != null select t).ToList().ForEach((t) =>
{
t.IsActive = false;
});
});

You are selecting lists that are null
where t == null
Should the condition be
where t != null

A simple approach. No need to check for null.
s.ForEach((x)=>
{
x.IsActive = false;
x.TestList.Foreach((t)=>{t.IsActive = false});
});

You don't necessarily need an inner loop since it looks like you're deactivating all nested TestList items. You can just have two separate loops:
foreach(var item in List)
item.IsActive = false;
foreach(var item in List.Where(x => x.TestList != null).SelectMany(x => x.TestList))
item.IsActive = false;
Note that SelectMany "flattens" the inner lists into a single IEnumerable<T>.

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

Reduce execution time in two foreach loop

//Get linked claim for children list from ClaimLink
foreach (var claim in processedClaims)
{
if (claim.Children == null)
{
claim.Children = new List<Claim>();
}
var claimRelationList = newClaimLink.Where(k=> k.ClaimLinkId == claim.Id).ToList();
if (claimRelationList.Any())
{
//Get the claim for all selected ClaimLink
foreach (var claimLink in claimRelationList)
{
var newChildren = claims.Where(p => p.Id == claimLink.ClaimId).ToList();
claim.Children = claim.Children != null && claim.Children.Any() ? newChildren.Concat(claim.Children) : newChildren;
}
}
}
I want to reduce the execution time in above two foreach loop. Is there have better way than this?
You can remove the if (claimRelationList.Any()) condition as the following foreach will not iterate over an empty list.
You already know that claim.Children is not null within that for each because you initialized it above. So I would replace
claim.Children = claim.Children != null && claim.Children.Any() ? newChildren.Concat(claim.Children) : newChildren;
With
claim.Children.AddRange (newChildren).
Multiple options i see at first sight:
don't call ToList(), not necessary here unless you have some sort of query executing in the background, see comment of #Shelby115
newClaimLink.Where(k=> k.ClaimLinkId == claim.Id) could be replaced by a dictionary created beforehand like newClaimLink.ToDictionary(k=> k.ClaimLinkId)
same goes for claims.Where(p => p.Id == claimLink.ClaimId)
Here is my best answer for above question.
//Get linked claim for children list from ClaimLink
foreach (var claim in processedClaims)
{
if (claim.Children == null)
{
claim.Children = new List<Claim>();
}
var claimRelationList = newClaimLink.Where(k=> k.ClaimLinkId == claim.Id).ToList();
if (claimRelationList.Any())
{
//Get the claim for all selected ClaimLink
var newChildren = claims.Where(o => claimRelationList.Select(p => p.ClaimId).Contains(o.Id));
if (newChildren.Any())
{
claim.Children = claim.Children != null && claim.Children.Any() ? newChildren.Concat(claim.Children) : newChildren;
}
}
}
I resolved my problem with lambda expression for the inner foreach loop then I could have to reduce the execution time more than 250ms.
Thank you for the helping me

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

Get the specific element in nested list using lambda in c#

Good days,
Lets say I have a static List<AClass> object (lets name it myStaticList) which contains an other list inside and that list contains an other list with CId and Name property.
What I need to do is
foreach(AClass a in myStaticList)
{
foreach(BClass b in a.bList)
{
foreach(CClass c in b.cList)
{
if(c.CId == 12345)
{
c.Name = "Specific element in static list is now changed.";
}
}
}
}
Can I achieve this with LINQ Lambda expressions?
Something like;
myStaticList
.Where(a=>a.bList
.Where(b=>b.cList
.Where(c=>c.CId == 12345) != null) != null)
.something logical
.Name = "Specific element in static list is now changed.";
Please note that i want to change the property of that specific item in the static list.
You need SelectMany to flatten your lists:
var result = myStaticList.SelectMany(a=>a.bList)
.SelectMany(b => b.cList)
.FirstOrDefault(c => c.CId == 12345);
if(result != null)
result.Name = "Specific element in static list is now changed.";;
Use SelectMany (excellent post here)
var element = myStaticList.SelectMany(a => a.bList)
.SelectMany(b => b.cList)
.FirstOrDefault(c => c.CId == 12345);
if (element != null )
element.Name = "Specific element in static list is now changed.";
var item = (from a in myStaticList
from b in a.bList
from c in b.cList
where c.CID = 12345
select c).FirstOrDefault();
if (item != null)
{
item.Property = "Something new";
}
You can use SelectMany also, but it's not straightforward.

Find an item in a list by LINQ

Here I have a simple example to find an item in a list of strings. Normally I use a for loop or anonymous delegate to do it like this:
int GetItemIndex(string search)
{
int found = -1;
if ( _list != null )
{
foreach (string item in _list) // _list is an instance of List<string>
{
found++;
if ( string.Equals(search, item) )
{
break;
}
}
/* Use an anonymous delegate
string foundItem = _list.Find( delegate(string item) {
found++;
return string.Equals(search, item);
});
*/
}
return found;
}
LINQ is new for me. Can I use LINQ to find an item in the list? If it is possible, how?
There are a few ways (note that this is not a complete list).
Single will return a single result, but will throw an exception if it finds none or more than one (which may or may not be what you want):
string search = "lookforme";
List<string> myList = new List<string>();
string result = myList.Single(s => s == search);
Note that SingleOrDefault() will behave the same, except it will return null for reference types, or the default value for value types, instead of throwing an exception.
Where will return all items which match your criteria, so you may get an IEnumerable<string> with one element:
IEnumerable<string> results = myList.Where(s => s == search);
First will return the first item which matches your criteria:
string result = myList.First(s => s == search);
Note that FirstOrDefault() will behave the same, except it will return null for reference types, or the default value for value types, instead of throwing an exception.
If you want the index of the element, this will do it:
int index = list.Select((item, i) => new { Item = item, Index = i })
.First(x => x.Item == search).Index;
// or
var tagged = list.Select((item, i) => new { Item = item, Index = i });
int index = (from pair in tagged
where pair.Item == search
select pair.Index).First();
You can't get rid of the lambda in the first pass.
Note that this will throw if the item doesn't exist. This solves the problem by resorting to nullable ints:
var tagged = list.Select((item, i) => new { Item = item, Index = (int?)i });
int? index = (from pair in tagged
where pair.Item == search
select pair.Index).FirstOrDefault();
If you want the item:
// Throws if not found
var item = list.First(item => item == search);
// or
var item = (from item in list
where item == search
select item).First();
// Null if not found
var item = list.FirstOrDefault(item => item == search);
// or
var item = (from item in list
where item == search
select item).FirstOrDefault();
If you want to count the number of items that match:
int count = list.Count(item => item == search);
// or
int count = (from item in list
where item == search
select item).Count();
If you want all the items that match:
var items = list.Where(item => item == search);
// or
var items = from item in list
where item == search
select item;
And don't forget to check the list for null in any of these cases.
Or use (list ?? Enumerable.Empty<string>()) instead of list.
Do you want the item in the list or the actual item itself (would assume the item itself).
Here are a bunch of options for you:
string result = _list.First(s => s == search);
string result = (from s in _list
where s == search
select s).Single();
string result = _list.Find(search);
int result = _list.IndexOf(search);
If it really is a List<string> you don't need LINQ, just use:
int GetItemIndex(string search)
{
return _list == null ? -1 : _list.IndexOf(search);
}
If you are looking for the item itself, try:
string GetItem(string search)
{
return _list == null ? null : _list.FirstOrDefault(s => s.Equals(search));
}
This method is easier and safer
var lOrders = new List<string>();
bool insertOrderNew = lOrders.Find(r => r == "1234") == null ? true : false
How about IndexOf?
Searches for the specified object and returns the index of the first occurrence within the list
For example
> var boys = new List<string>{"Harry", "Ron", "Neville"};
> boys.IndexOf("Neville")
2
> boys[2] == "Neville"
True
Note that it returns -1 if the value doesn't occur in the list
> boys.IndexOf("Hermione")
-1
This will help you in getting the first or default value in your LINQ List search
var results = _List.Where(item => item == search).FirstOrDefault();
This search will find the first or default value, which it will return.
I used to use a Dictionary which is some sort of an indexed list which will give me exactly what I want when I want it.
Dictionary<string, int> margins = new Dictionary<string, int>();
margins.Add("left", 10);
margins.Add("right", 10);
margins.Add("top", 20);
margins.Add("bottom", 30);
Whenever I wish to access my margins values, for instance, I address my dictionary:
int xStartPos = margins["left"];
int xLimitPos = margins["right"];
int yStartPos = margins["top"];
int yLimitPos = margins["bottom"];
So, depending on what you're doing, a dictionary can be useful.
If we need to find an element from the list, then we can use the Find and FindAll extensions method, but there is a slight difference between them. Here is an example.
List<int> items = new List<int>() { 10, 9, 8, 4, 8, 7, 8 };
// It will return only one 8 as Find returns only the first occurrence of matched elements.
var result = items.Find(ls => ls == 8);
// this will returns three {8,8,8} as FindAll returns all the matched elements.
var result1 = items.FindAll(ls => ls == 8);
Here is one way to rewrite your method to use LINQ:
public static int GetItemIndex(string search)
{
List<string> _list = new List<string>() { "one", "two", "three" };
var result = _list.Select((Value, Index) => new { Value, Index })
.SingleOrDefault(l => l.Value == search);
return result == null ? -1 : result.Index;
}
Thus, calling it with
GetItemIndex("two") will return 1,
and
GetItemIndex("notthere") will return -1.
Reference: linqsamples.com
Try this code:
return context.EntitytableName.AsEnumerable().Find(p => p.LoginID.Equals(loginID) && p.Password.Equals(password)).Select(p => new ModelTableName{ FirstName = p.FirstName, UserID = p.UserID });
You can use FirstOfDefault with the Where LINQ extension to get a MessageAction class from the IEnumerable. Reme
var action = Message.Actions.Where(e => e.targetByName == className).FirstOrDefault<MessageAction>();
where
List<MessageAction> Actions { get; set; }
One more way to check the existence of an element in a List<string>:
var result = myList.Exists(users => users.Equals("Vijai"))
You want to search an object in object list.
This will help you in getting the first or default value in your Linq List search.
var item = list.FirstOrDefault(items => items.Reference == ent.BackToBackExternalReferenceId);
or
var item = (from items in list
where items.Reference == ent.BackToBackExternalReferenceId
select items).FirstOrDefault();

Categories

Resources