Best way to write this in Linq - c#

How do I refactor this in LINQ. I am working towards embracing good coding practices. My tds object looks like this:
tds -> BuildingName(List) -> buildingFloor(string)
What I am accomplishing with the nested foreach loop is reading the buildingFloors into a list.
List<string> bname = new List<string>();
foreach (var building in tds) {
foreach (var x in building.BuildingName) {
bname.Add(x);
}
}

You can do it with SelectMany which will flatten your items
List<string> bname = tds.SelectMany(b => b.BuildingName).ToList();

Use Enumerable.SelectMany to flatten your list like:
List<string> bname = tds.SelectMany(r=> r.BuildingName).ToList();

What you're looking for is SelectMany.
var bname = buildings.SelectMany(b => b.BuildingName);
Note, if you're going to be enumerating over the result multiple times with foreach then you will probably want to ToList() it, so you have a hard list rather than an enumerable that is executed every time you enumerate it.
var bname = buildings.SelectMany(b => b.BuildingName).ToList();

something like this I suppose:
var bname = tds.SelectMany(x => x.BuildingName);
And if you need a List call .ToList() at the end

var bname = tds.Select( x=> x.buildingName).ToList() ;
edit: I did not see the inner foreach while on my commute to work, it is indeed
var bname = tds.SelectMany(x=> x.BuildingName).ToList();

using query-syntax:
List<string> bname =
(from building in tds
from x in building.BuildingName
select x)
.ToList()

Related

How to use Linq to check if a list of strings contains any string in a list

I'm constructing a linq query that will check is a string in the DB contains any of the strings in a list of strings.
Something like.
query = query.Where(x => x.tags
.Contains(--any of the items in my list of strings--));
I'd also like to know how many of the items in the list were matched.
Any help would be appreciated.
Update: I should have mentioned that tags is a string not a list. And I am adding on a couple more wheres that are not related to tags before the query actually runs. This is running against entity framework.
EDIT: This answer assumed that tags was a collection of strings...
It sounds like you might want:
var list = new List<string> { ... };
var query = query.Where(x => x.tags.Any(tag => list.Contains(tag));
Or:
var list = new List<string> { ... };
var query = query.Where(x => x.tags.Intersect(list).Any());
(If this is using LINQ to SQL or EF, you may find one works but the other doesn't. In just LINQ to Objects, both should work.)
To get the count, you'd need something like:
var result = query.Select(x => new { x, count = x.tags.Count(tag => list.Contains(tag)) })
.Where(pair => pair.count != 0);
Then each element of result is a pair of x (the item) and count (the number of matching tags).
I've done something like this before:
var myList = new List<string>();
myList.Add("One");
myList.Add("Two");
var matches = query.Where(x => myList.Any(y => x.tags.Contains(y)));
like this:
List<string> list = new List<string>();
list.Add("One");
list.Add("Two");
var result = query.Where(x => list.Contains(x.tags));
I am not quite sure from your question if x.tags is a string or list, if it is a list Jon Skeet's answer is correct. If I understand you correctly though x.tags is a string of strings. If so then the solution is:
list.Any(x => x.tags.IndexOf(x) > -1)
to count them do
list.Count(x => x.tags.IndexOf(x) > -1)
var t = new List<string> { "a", "b", "c" };
var y = "a b d";
var res = y.Count(x => t.Contains(x.ToString()));
I faced a similar problem recently and here's how I managed to work it out:
var list = [list of strings];
if (list != null && list.Any())
{
queryable = queryable.Where(x => x.tags != null);
var tagQueries = new List<IQueryable<WhateverTheDbModelIs>>();
foreach (var element in list)
{
tagQueries.Add(queryable.Where(x => x.tags.Contains(element)));
}
IQueryable<WhateverTheDbModelIs> query = tagQueries.FirstOrDefault();
foreach (var tagQuery in tagQueries)
{
query = query.Union(tagQuery);
}
queryable = queryable.Intersect(query);
}
probably not the best option but something a less experienced developer can understand and use

How to use Linq instead of foreach to Group and Count

I have 2 Lists, one for Players and another for Coaches.
To count number of Players belong to a Coach, I used:
var g = AllePlayer.GroupBy(play=> play.coachNumer);
foreach (var grp in g)
{
foreach (Coach co in AlleCoaches)
{
if (co.coachNumer== grp.Key)
{
co.NumOfPlayer= grp.Count();
}
}
}
Now I want to know if there is a nice way to put the lover parts with "foreach" in a nice Linq syntax to avoid this "foreach" loops.
Thank you in advance!
You could change the statement around a little bit. Since ultimately you want to change a property on each coach, it's easiest to loop through that list, as in:
foreach (Coach co in AlleCoaches)
{
co.NumOfPlayer= AllePlayer.Where(p => p.coachNumber == co.coachNumber)
.Count();
}
AlleCoaches.ToList()
.ForEach(n=>n.NumOfPlayer=AllePlayer.Where(n=>coachNumer==n.coachNumer).Count());
This would be a simpler approach:
var query = AllePlayer.GroupBy(player => player.coachNumer,
(coach, players => new {
Coach = coach,
Count = players.Count() }));
That will give you a sequence where each element is the coach and the number of players for that coach.
Then you could iterate over the result, and assign the value into Coach.NumOfPlayer, but do you really need to? If you do, this will do it:
foreach (var pair in query)
{
pair.Coach.NumOfPlayer = pair.Count;
}
Personally it doesn't feel like "number of players" should be part of the Coach type to start with...
var g = AllePlayer.TakeWhile(play=> ( play.coachNumer!=null));
You may take whatever logic you need but syntax would be the same.
var count = g.Count();

Remove elements from one List<T> that are found in another

I have two lists
List<T> list1 = new List<T>();
List<T> list2 = new List<T>();
I want remove all elements from list1, which also exist in list2. Of course I can loop through the first loop looking for each element in list2, but I am looking for elegant solution.
Thanks!
To change the actual list1 in place, you could use
list1.RemoveAll(item => list2.Contains(item));
You might instead prefer to simply have a query over the lists without modifying either
var result = list1.Except(list2);
LukeH makes a good recommendation in the comments. In the first version, and if list2 is particularly large, it might be worth it to load the list into a HashSet<T> prior to the RemoveAll invocation. If the list is small, don't worry about it. If you are unsure, test both ways and then you will know.
var theSet = new HashSet<YourType>(list2);
list1.RemoveAll(item => theSet.Contains(item));
With LINQ:
var result = list1.Except(list2);
list1.RemoveAll( item => list2.Contains(item));
Description
I think you mean the generic type List<Type>. You can use Linq to do this
Sample
List<string> l = new List<string>();
List<string> l2 = new List<string>();
l.Add("one");
l.Add("two");
l.Add("three");
l2.Add("one");
l2.Add("two");
l2.Add("three");
l2.Add("four");
l2.RemoveAll(x => l.Contains(x));
More Information
MSDN - List.RemoveAll Method
var result = list1.Except(list2);
Using LINQ you can do this:
List1.RemoveAll(i => !List2.Contains(i));
If you want to remove a list of objects (list2) from another list (list1) use:
list1 = list1.Except(list2).ToList()
Remember to use ToList() to convert IEnumerable<T> to List<T>.
var NewList = FirstList.Where(a => SecondList.Exists(b => b.ID != a.ID));
Using LINQ

C# list question

What would be the nice way to make the following action:
List<IEnumerable<T>> listOfEnumerables = Get...();
List<T> listOfObjects = new List<T>();
// I want 'listOfObjects' to contain every element from every enumerable
// in 'listOfEnumerables'.
Is there any beautiful way to make this instead of the following:
foreach (var enumerable in listOfEnumerables)
{
listOfObjects.AddRange(enumerable);
}
Thank you.
You can use LINQ:
List<T> listOfObjects = listOfEnumerables.SelectMany(s => s).ToList();
listOfEnumerables.ForEach(i => listOfObjects.AddRange(i));

Remove items from one list in another

I'm trying to figure out how to traverse a generic list of items that I want to remove from another list of items.
So let's say I have this as a hypothetical example
List<car> list1 = GetTheList();
List<car> list2 = GetSomeOtherList();
I want to traverse list1 with a foreach and remove each item in List1 which is also contained in List2.
I'm not quite sure how to go about that as foreach is not index based.
You can use Except:
List<car> list1 = GetTheList();
List<car> list2 = GetSomeOtherList();
List<car> result = list2.Except(list1).ToList();
You probably don't even need those temporary variables:
List<car> result = GetSomeOtherList().Except(GetTheList()).ToList();
Note that Except does not modify either list - it creates a new list with the result.
You don't need an index, as the List<T> class allows you to remove items by value rather than index by using the Remove function.
foreach(car item in list1) list2.Remove(item);
In my case I had two different lists, with a common identifier, kind of like a foreign key.
The second solution cited by "nzrytmn":
var result = list1.Where(p => !list2.Any(x => x.ID == p.ID && x.property1 == p.property1)).ToList();
Was the one that best fit in my situation.
I needed to load a DropDownList without the records that had already been registered.
Thank you !!!
This is my code:
t1 = new T1();
t2 = new T2();
List<T1> list1 = t1.getList();
List<T2> list2 = t2.getList();
ddlT3.DataSource= list2.Where(s => !list1.Any(p => p.Id == s.ID)).ToList();
ddlT3.DataTextField = "AnyThing";
ddlT3.DataValueField = "IdAnyThing";
ddlT3.DataBind();
I would recommend using the LINQ extension methods. You can easily do it with one line of code like so:
list2 = list2.Except(list1).ToList();
This is assuming of course the objects in list1 that you are removing from list2 are the same instance.
list1.RemoveAll(l => list2.Contains(l));
You could use LINQ, but I would go with RemoveAll method. I think that is the one that better expresses your intent.
var integers = new List<int> { 1, 2, 3, 4, 5 };
var remove = new List<int> { 1, 3, 5 };
integers.RemoveAll(i => remove.Contains(i));
Solution 1 : You can do like this :
List<car> result = GetSomeOtherList().Except(GetTheList()).ToList();
But in some cases may this solution not work. if it is not work you can use my second solution .
Solution 2 :
List<car> list1 = GetTheList();
List<car> list2 = GetSomeOtherList();
we pretend that list1 is your main list and list2 is your secondry list and you want to get items of list1 without items of list2.
var result = list1.Where(p => !list2.Any(x => x.ID == p.ID && x.property1 == p.property1)).ToList();
As Except does not modify the list, you can use ForEach on List<T>:
list2.ForEach(item => list1.Remove(item));
It may not be the most efficient way, but it is simple, therefore readable, and it updates the original list (which is my requirement).
I think it would be quick to convert list A to a dictionary and then foreach the second list and call DictA.Remove(item) otherwise I think most solutions will cause many iterations through list A either directly or under the covers.
If the lists are small, it probably won't matter.
In case you have two different list with different DataModals
List<FeedbackQuestionsModel> feedbackQuestionsList = new();
List<EmployeesFeedbacksQuestionsModel> employeeQuestionsList = new();
var resultList = feedbackQuestionsList.Where(p => !employeeQuestionsList.Any(x => x.Question == p.Question)).ToList();
feedbackQuestionsList = resultList.ToList();
Here ya go..
List<string> list = new List<string>() { "1", "2", "3" };
List<string> remove = new List<string>() { "2" };
list.ForEach(s =>
{
if (remove.Contains(s))
{
list.Remove(s);
}
});

Categories

Resources