I'm wanting to only display a list of CourseNo with no duplicates using LINQ, but I can't quite figure the syntax out.
this.Distinct_CourseNo = (from c in Roster_Sections
select c).Distinct(CourseNo).ToList;
The SQL equivalent would be something along the lines of:
SELECT DISTINCT CourseNo
FROM Roster_Sections
All the provided answers are applicable only if you have moreLINQ. However, you can try this instead:
this.Distinct_CourseNo = (from c in Roster_Sections
group c by c.CourseNo into g
select g.First()).ToList();
using select c will include all columns in the Roster_Sections, thus Distinct() will not work if atleast one row in a column is different from the other row.
this.Distinct_CourseNo = (from c in Roster_Sections
select c.CourseNo).Distinct().ToList();
or
this.Distinct_CourseNo = Roster_Sections.Distinct(c => c.CourseNo).ToList();
You’d pass Distinct a lambda describing what defines distinctness:
this.Distinct_CourseNo = Roster_Sections.Distinct(x => x.CourseNo).ToList();
If you mean to get a list of unique course numbers as opposed to a list of unique courses based off course number, 今 草 顿 웃’s answer is the way to go.
Related
please I'm working on a ASP.NET MVC project with Entity Framework.
I try to write a Linq Query that give me some data, this Query will join two entities and grouping by data, so the issue is when I try to get the properties of second joined entity I don't see them in Intellisense, I need these properties to select them.
What I try :
var R = (from N in SCHOOL_DB_Context.Con.NT_CTR join S in SCHOOL_DB_Context.Con.STGs on N.STG_nt equals S.CD_STG where N.CTR_nt==CTR group N by N.STG_nt into G select new NT_CTR_Anal { /*Here where I want to select some properties from second entity*/ } )
So please any help about this issue ?
Take a look at tis fragment:
group N by N.STG_nt into G
The part between by and into is the key(s), and similar to SQL there you have access to all aliases (variables) from from and join clauses. The name after into is LINQ specific and represents the alias (variable) for accessing the GroupBy result. But what is between group and 'by'? There is no SQL equivalent.
Well, the result of GroupBy is of type IGrouping<TKey, TElement>, which has property TKey Key and also is IEnumerable<TElement>. The TKey is comong from the expression between by and into, while TElement (which is what you can access through into variable is coming from the expression between group and by.
In your sample you've put N there, that`s why you have access only to its properties.
In order to have access to other properties, you would use the typical LINQ construct for "composite" things, which is anonymous type projection, e.g.
var R = (
from N in SCHOOL_DB_Context.Con.NT_CTR
join S in SCHOOL_DB_Context.Con.STGs on N.STG_nt equals S.CD_STG
where N.CTR_nt == CTR
group new { N, S } by N.STG_nt into G
select new NT_CTR_Anal
{
G.Key, // N.STG_nt
SomeNPropSum = G.Sum(e => e.N.SomeNProp),
SomeSPropSum = G.Sum(e => e.S.SomeSProp),
};
As you can see, now you have access to both N and S properties inside grouping aggregate methods.
I have a need to filter a large collection of objects (in memory) to select only those which meet ALL of the selected categories.
This is essentially the SQL query I'm looking to replicate, but I've been unable to come up with a good C# alternative:
select distinct o.ObjectId
from Object o
join ObjectCategories oc on oc.ObjectId = o.ObjectId
where oc.CategoryId in (1)
and oc.CategoryId in (2)
and oc.CategoryId in (3)
... and so on...
...where 1, 2, and 3 represent the values in an indeterminate number of user-selected categories.
Have your user selected category ID's in a List and then you can use Contains.
select distinct o.ObjectId
from Object o
join ObjectCategories oc on oc.ObjectId = o.ObjectId
where yourCategoryList.Contains(oc=>oc.categoryID);
var results = ObjectCategories.Where(t2 => ObjectList.Any(t1 => t2.Contains(t1)) == true)
you can count the number of matches and if it is equal to the list you are checking against, then you have all the matches.
Consider using Dynamic LINQ. It allows you to use string expressions instead of lambda expressions. You should be able to do what you want using something similar to:
var qry = ObjectCategories.Where(
"ObjectList.CategoryId.Contains(1) AND ObjectList.CategoryId.Contains(2) ..."
);
There is a pretty solid implemention of Dynamic LINQ here: https://github.com/NArnott/System.Linq.Dynamic
How can I go about converting this SQL statement to LINQ:
SELECT [Content].[Content], [Content].ListOrder, [Content].ContentTypeId,
[Content].ContentId
FROM [Content] INNER JOIN
GroupContentPermission ON [Content].ContentId = GroupContentPermission.ContentId
WHERE GroupContentPermission.GroupId IN
(SELECT GroupId FROM GroupUser WHERE GroupUser.UserId = 169)
Translation to LINQ is generally pretty straightforward except for one special trick in the case of your query. You can translate your select, where, and from statements in a natural way as shown below. In the case of an IN statement though, you have to get the results from the inner subquery first, and then check if the inner subquery .Contains the value you want to check.
var groups =
(from gu in GroupUser
where gu.UserId == 169
select gu.GroupId).ToList();
var result =
from p in GroupContentPermission
join c in Content on p.ContentId equals c.ContentId
where groups.Contains(p.GroupId)
select new { c.Content, c.ListOrder, c.ContentTypeID, c.ContentId };
// result should contain the same results as the SQL query
Here are some other resources you may find helpful as well (you can find many more resources and tutorials on LINQ if you do a quick google search. There are literally thousands):
Linqer, a SQL to LINQ converter.
LinqPAD, a simple .NET/LINQ tester for rapid experimentation
ScottGu's definitive guide to Using LINQ To SQL
Related SO question: What are some good LINQ resources?, which references a tutorial called 101 LINQ Samples.
Assuming you already link the tables with foreign keys in your model (DBML/EntityFrameworks):
Contents.Where(x => x.GroupContentPermission.GroupUser.UserId == 169).Select(x => new {
x.Content,
x.ListOrder,
x.ContentTypeId,
x.ContentId })
or preferrably just grab the full Content object, and use any column you want:
var contents = Contents.Where(x => x.GroupContentPermission.GroupUser.UserId == 169).ToList();
foreach (var content in contents)
Console.Write(content.Content);
How to select from a list with Linq, based on id and datetime value. I want the latest item from each id.
So I have a list that has an ID and a date time for each object.
I know how to get just the items that are from a certain id.
var foundListings = (from listing in db.Listings
where listing.UserID == idToFind
select listing);
But what I want to do is get the latest item from each ID.
So if I have a List with let's say 5 Listings and their are only 2 ids in there. I want to query and get just 2 items with the latest date.
Is this possible with Linq? I am certain I can do it iteratively going through the list with a for loop but wanted to see if I could do it with Linq and this is a little beyond my linq skills.
You'll probably want to use group by to create groups based on the ID and then select minimum from each group. I didn't test it, but the structure should look like this:
var q = from listing in db.Listings
group by listing.UserID into g
select g.OrderBy(el => el.Value).First();
Using the OrderBy clause is a bit unfortunate, because it implies that you want to search all items. Unfortunatelly, there is no operator to return the item that is largest by some property. Alternatively, you could first find maximum and then find some element which has that value:
var q = from listing in db.Listings
group by listing.UserID into g
let max = g.Max(el => el.Value)
select g.Where(el => el.Value == max).First();
This may be slightly more efficient (especially for in-memory runs) because it doesn't need to sort the entire group.
var result = from listing in db.Listings
group listing by listing.ID into g
select g.OrderByDescending(l => l.DateTime).First();
I am using LinqPad to learn Linq by querying the NetFlix OData source.
(BTW I know their is a similar question already on SO...didn't help me).
Here is the query I got working which is awesome.
from x in Titles
//where x.Rating=="PG"
where x.Instant.Available==true
where x.AverageRating>=4.0
//where x.Rating.StartsWith("TV")
//where x.Genres.First (g => g.Name.Contains("Family") ) //(from y in Genres where y.Name.Contains("Family") select y)
//where x.Genres.First (g => g.Name=="")
//orderby x.Name
orderby x.AverageRating descending
//select x
//)
select new {x.Name, x.Rating, x.AverageRating, x.ShortSynopsis}
(Pardon all the comments...it is a testament to the fact I am experimenting and that I will change the query for various needs).
There are two thing I cannot figure out.
First. Let's say I only want to return the first 10 results.
Second (and most importantly). I want to filter by a partial string of the genre. Each title contains a Genres collection. I want to show only Genres where the Name contains a certain string (like "Family"). Even better filter using Titles where genre.name.contains "firstFilter" AND "secondFilter".
Basically, I want to filter by genre(s) and I cannot figure out how to do it since Title contains its own Genres collection and I cannot figure out how to return only title that are in one or more genres of the collection.
Thanks for your help!
ps...it seems that Netflix OData source does not support Any operator.
Seth
To return the first 10 results, surround your code above with parentheses and put a .Take(10) on the end
var foo = ( from x in Titles... ).Take(10);
There is no way to do take using query syntax in C# currently.
As for the genre filter, as klabranche points out, oData does not support many of the same Linq constructs you can use locally with a regular IEnumerable or IQueryable.
klabranche's solution doesn't support contains. It does however make 2 round trips to the server to get results. (see my comment on his answer as to why this seems necessary)
Here is an alternative which makes one roundtrip to the server to get data, then it processes that data locally. Because some of the query runs locally, you can use string.Contains, "or" clauses, and other goodness.
The downside of this approach is it retrieves more data over the wire than is needed to answer the query. On the other hand, it's easy to understand and it works.
When I combine "Family" and "Children", it returns 21 results.
var oDataQuery = from x in Titles
where x.AverageRating >= 4
&& x.Instant.Available==true
orderby x.AverageRating descending
select new {x.Name, x.Rating, x.AverageRating, x.ShortSynopsis, x.Genres};
var localQuery = from o in oDataQuery.ToList()
where o.Genres.Any(g => g.Name.Contains("Family"))
&& o.Genres.Any(g => g.Name.Contains("Children"))
select new {o.Name, o.Rating, o.AverageRating, o.ShortSynopsis };
localQuery.Dump();
OData and the Netflix API support the Take() and Contains() methods:
from t in Titles
where t.Name.Contains("Matrix")
select t
(from t in Titles
where t.Name.Contains("Matrix")
select t).Take(10)
To get the first 10:
(from x in Titles
where x.Instant.Available==true
where x.AverageRating>=4.0
orderby x.AverageRating descending
select new {x.Name, x.Rating, x.AverageRating, x.ShortSynopsis}
).Take(10)
To filter by a single genre (Not what you want...):
from g in Genres
from t in g.Titles
where g.Name == "Horror"
where t.Instant.Available==true
where t.AverageRating >=4.0
orderby t.AverageRating descending
select new {t.Name, t.Rating, t.AverageRating, t.ShortSynopsis}
However, you wanted to have multiple genres BUT OData doesn't support Select Many queries which is why contains fails or trying to OR the Genre Name.
Below fails because contains returns many...
var q1 = from g in Genres
from t in g.Titles
where g.Name.Contains("Horror")
where t.Instant.Available==true
where t.AverageRating >=4.0
orderby t.AverageRating descending
select new {t.Name, t.Rating, t.AverageRating, t.ShortSynopsis};
To filter by multiple genres I found you can use a Concat or Union query (in LinqPad be sure to change to C# statements not expression):
var q1 = from g in Genres
from t in g.Titles
where g.Name=="Horror"
where t.Instant.Available==true
where t.AverageRating >=4.0
orderby t.AverageRating descending
select new {t.Name, t.Rating, t.AverageRating, t.ShortSynopsis};
var q2 = from g in Genres
from t in g.Titles
where g.Name=="HBO"
where t.Instant.Available==true
where t.AverageRating >=4.0
orderby t.AverageRating descending
select new {t.Name, t.Rating, t.AverageRating, t.ShortSynopsis};
var concat = q1.ToList().Concat(q2);
//var union = q1.Union(q2);
By unioning the two queries it will remove duplicates but these are what you want If I understand you correctly in that you want movies that are only in both genres?
In that case you will want to use Concat which will return all records.
Now you just need to find records that are in the query more than once and you have your results:
var results = from c in concat
group c by c.Name into grp
where grp.Count() > 1
select grp;