I have a list of Objects, where every object has a "Name" and different other stuff. I want to filter out those objects who don't have a unique name in that List.
Is there a LINQ Statement where I can "Union()" all the resulting groups and just return a IEnumerable of my objects?
Like
IEnumerable<MyObject> Results = (from x in Objects
group x by x.Name into g
where g.Count() > 1
select g)
.COMBINE_OR_WHATEVER();
Thanks!
Yes, there is. You can use SelectMany.
IEnumerable<MyObject> Results = (from x in Objects
group x by x.Name into g
where g.Count() > 1
select g)
.SelectMany(x => x);
I think you want only the object with unique names ("I want to filter out those objects who don't have a unique name in that List"):
var result = Objects.GroupBy(o => o.Name)
.Where(grp => grp.Count() == 1)
.SelectMany(grp => grp);
Related
I'm still very new with LINQ. I have the following "simplified" data structure:
List<List<Field>> myData = new List<List<Field>>();
Field consists of two string members, Type and Name.
My goal is to get a List<string> containing all distinct Name corresponding to a given Type. My first approach is this:
var test = myData
.Where(a => a.FindAll(b => b.Type.Equals("testType"))
.Select(c => c.Name)
.Distinct());
Does somebody have a hint for me? =)
You just need to use SelectMany to flatten your list of lists and then proceed as normal
var test = myData.SelectMany(x => x)
.Where(x => x.Type == "testType")
.Select(x => x.Name)
.Distinct()
.ToList();
Or in query syntax
var test = (from subList in myData
from item in subList
where item.Type == "testType"
select item.Name).Distinct().ToList();
Another way to do it using query notation:
var test= from list in myData
from e in list
where e.Type=="testType"
group e.Name by e.Name into g
select g.Key;
But is better go for one of the #juharr's solutions
I'm trying to select the top five most frequent values and their count in my table and return them in a Dictionary. I'm able to get the values in sql:
SELECT top 5
SR_Status,
COUNT(SR_Status) AS 'value_count'
FROM
ServiceRequests
GROUP BY
SR_Status
ORDER BY
'value_count' DESC;
How to convert to linq and assign to Dictionary
You do not specify if you are using Linq2Sql or Linq2Objects, so, let's just assume linq then. Try something like this (see the comments for each line):
var result = (from s in ServiceRequests // define the data source
group s by s.SR_Status into g // group all items by status
orderby g.Count() descending // order by count descending
select new { g.Key, Total = g.Count() }) // cast the output
.Take(5) // take just 5 items
.ToDictionary(x => x.Key, x => x.Total); // cast to dictionary
Obs: I didn't test it.
Assuming you are using Entity Framework and have an EntitySet named ServiceRequests and all the properties names are the same as the column names:
var result = context.ServiceRequests.GroupBy(sr => sr.SR_Status)
.Select(g => new { Key = g.Key, Count = g.Count() })
.OrderByDescending(kv => kv.Count)
.Take(5)
.ToList();
I have the following objects:
public interface ITray
{
int OrderNo {get; set;}
IEnumerable<ITrayItem> TrayItems {get;}
}
public interface ITrayItem
{
int Aisle {get; set;}
}
Now, I have two List objects,
List<ITray> selectedTrays
List<ITray> poolTrays
What I am trying to do is for each element in poolTrays, I want to compare the Aisles that are in the list of selected trays. If all of the Aisles match, I want to add it to a list of trays to return.
I'm just tying myself in knots a bit trying to get the linq working with the querying of a property of a collection inside a list and returning the items in the list that match.
This is what I have at the moment:
List<int> selectedAisles = (from tray in selectedTrays
from item in tray.TrayItems
select item.Aisle).Distinct().ToList()
List<ITray> trayswithMatchingAisles =
(from t in poolTrays
from item in t.TrayItems
where selectedAisles.Contains(item.Aisle)
select t).ToList();
So, if I have selected Trays A, B, C with aisles in brackets
A[1,2,3] B[4,5,6] c[7,8,9]
then a poolTray with TrayItems in aisles [7,9] should return successfully, but a pool tray with TrayItems [7,8,9,10] should not be returned in the list.
At the moment, I am passing in (just) [7,9] in my poolTray list, and 2 instances of it are returned in my Linq query
Something like this should work:
List<int> selectedAisles =
(from tray in selectedTrays
from item in tray.TrayItems
select item.Aisle)
.Distinct().ToList();
List<ITray> trayswithMatchingAisles =
(from t in poolTrays
where t.TrayItems.Select(i => i.Aisle)
.All(a => selectedAisles.Contains(a))
select t)
.ToList();
But this can be simplified to:
List<ITray> trayswithMatchingAisles =
(from t in poolTrays
where t.TrayItems.Select(i => i.Aisle)
.All(a => selectedTrays
.SelectMany(s => s.TrayItems)
.Select(i => i.Aisle)
.Contains(a))
select t)
.ToList();
Or this:
List<ITray> trayswithMatchingAisles = poolTrays
.Where(t => t.TrayItems
.Select(i => i.Aisle)
.All(a => selectedTrays
.SelectMany(s => s.TrayItems)
.Select(i => i.Aisle)
.Contains(a)))
.ToList();
I think you need to use the "SelectMany" extension, this is to flat queries that return lists of lists.
For example:
var distinctSelectedItems = selectedTrays.SelectMany(t => t.TrayItems).Select(ti => ti.Aisle).Distinct();
bool success = poolTrays.SelectMany(t => t.TrayItems).All(ti => distinctSelectedItems.Contains(ti.Aisle));
You can also create a HashSet, in order to have O(1) performance, instead of O(n) for the List.Contains.
var distinctSelectedItems = new HashSet<int>(selectedTrays.SelectMany(t => t.TrayItems).Select(ti => ti.Aisle));
bool success = poolTrays.SelectMany(t => t.TrayItems).All(ti => distinctSelectedItems.Contains(ti.Aisle));
Good luck.
var result = poolTrays.Where(x => selectedTrays.Any(z=>z.TrayItems.Select(y => y.Aisle)
.Intersect(x.TrayItems.Select(k => k.Aisle))
.Count() == x.TrayItems.Count()));
int itemCount=3;
prod.Add("P1");
prod.Add("P2");
prod.Add("P1");
prod.Add("P2");
prod.Add("P1");
prod.Add("P3");
In this prod list I want to get count of each item and if the count matches the itemCount then need to put it in an array.
In this case only P1 must be put to array.
Can anyone help me out? I want code in C#.
If prod is a IEnumerable<string>, you can do this with linq
var results =
(from s in prod
group s by s into g
where g.Count() == itemCount
select g.Key)
.ToArray();
I assumed that prod is List<string> or IEnumerable<string> in general:
var items = prod.GroupBy(x => x)
.Where(g => g.Count() == itemCount)
.Select(g => g.Key)
.ToArray();
I have 2 Lists of different objects eg List and List. I want to remove all objects in first list whos value of a field doesn't match on a value of a field in the second list.
Eg I want to remove all Type1 objects from the first list whos Type1.name (string) member doesnt match a Type2.id (string) member in the second list.
Is this possible with LINQ ?
LINQ isn't about modifying existing collections - it's about running queries. If you need to change a list in place, you might want something like:
HashSet<string> ids = new HashSet<string>(list2.Select(x => x.Id));
list1.RemoveAll(x => !ids.Contains(x.Name));
In "normal" LINQ you could do this with:
// I'm assuming no duplicate IDs in list2
var query = (from x in list1
join y in list2 on x.Name equals y.Id
select x).ToList();
You can also use lambda:
var query = (list1.Join(list2, x => x.Name, y => y.Id, (x, y) => x)).ToList();
or
var query = (Enumerable.Join(list1, list2, x => x.Name, y => y.Id, (x, y) => x)).ToList();