I have a list of objects, the object contains a datetime.
I want to use LINQ to exclude the object with the latest datetime.
I'm trying something like:
var excludedList = testdata.Except(testdata.Max(c => c.registeredAt).FirstOrDefault()).ToList();
But it does not work, what should the correct linq be?
You could try something like this:
var excludedList = testdata.OrderByDescending(i => i.registeredAt).Skip(1).ToList();
This will sort the list by date, then skip the first item.
Here's a solution that doesn't perform a whole sort just to extract a single maximum value, and preserves the order of the sequence. It does still depend on the maximum value being unique.
var maxRegisteredAt = testdata.Max(c => c.registeredAt);
var excludedList = testdata
.Where(c => c.registeredAt != maxRegisteredAt)
.ToList();
This is one possible approach if duplicate registeredAt datetimes aren't possible:
var maxObj = testdata.OrderByDescending(x => x?.registeredAt).First();
var excludedList = testdata.FindAll(x => x != maxObj);
This keeps the original order.
Related
Given a List<string> How to return all records in an entity that has a field containing one or more words from the list.
I tried the below which does not work and I'm starting to go around in circles a bit:
List<string> searchwords = new List<string>() {"word1","word2"};
var results = context.activities
.Where(a => a.Title.Contains(searchwords.Any().ToString())).ToList();
The problem with your current code:
var results = context.activities.Where(a =>
a.Title.Contains(searchwords.Any().ToString())).ToList();
is that you have your needle and haystack backwards. The fact that you needed to call .ToString() on Any() should have tipped you off. Any() returns a bool, which you're casting to a string, so you're just checking whether Title contains the string "True". Definitely not what you want. You want something closer to:
var results = context.activities
.Where(a => searchwords.Any(searchWord => a.Title.Contains(searchWord)));
I have a list of Stores (of type ObservableCollection<Store>) and the Store object has a property called Features ( of type List<Feature> ). and the Feature object has a Name property (of type string).
To recap, a list of Stores that has a list of Features
I have a second collection of DesiredFeatures (of type List<string> ).
I need to use LINQ to give me results of only the stores that have all the DesiredFeatures. So far, I've only been able to come up with a query that gives me an OR result instead of AND.
Here's what that looks like:
var q = Stores.Where(s=> s.Features.Any(f=> DesiredFeatures.Contains(f.name)));
I know Intersect can help, and here's how I've used it:
var q = Stores.Where(s => s.Features.Intersect<Feature>(DesiredFeatures));
This is where I'm stuck, Intersect wants a Feature object, what I need to intersect is on the Feature.Name.
The goal is to end up with an ObservableCollection where each Store has all of the DesiredFeatures.
Thank you!
You've almost done what you need. A small refine would be to swap DesiredFeatures and s.Features.
var q = Stores.Where(s => DesiredFeatures.All(df => s.Features.Contains(df)));
It means take only those stores where desired features are all contained in features of the store.
I need to use LINQ to give me results of only the stores that have all the DesiredFeatures.
In other words, each desired feature must have a matching store feature.
I don't see how Intersect can help in this case. The direct translation of the above criteria to LINQ is like this:
var q = Stores.Where(s =>
DesiredFeatures.All(df => s.Features.Any(f => f.Name == df))
);
A more efficient way could be to use a GroupJoin for performing the match:
var q = Stores.Where(s =>
DesiredFeatures.GroupJoin(s.Features,
df => df, sf => sf.Name, (df, sf) => sf.Any()
).All(match => match)
);
or Except to check for unmatched items:
var q = Stores.Where(s =>
!DesiredFeatures.Except(s.Features.Select(sf => sf.Name)).Any()
);
Going on your intersect idea, the only way I thought of making this work was by using Select to get the Store.Features (List<Feature>) as a list of Feature Names (List<string>) and intersect that with DesiredFeatures.
Updated Answer:
var q = Stores.Where(s => s.Features.Select(f => f.Name).Intersect(DesiredFeatures).Any());
or
var q = Stores.Where(s => DesiredFeatures.Intersect(s.Features.Select(f => f.Name)).Any());
Old Answer (if DesiredFeatures is a List<Feature>):
var q = Stores.Where(s => s.Features.Select(f => f.Name).Intersect(DesiredFeatures.Select(df => df.Name)).Any());
Two things you want your code to perform.
var q = Stores.Where(s=> s.Features.All(f=> DesiredFeatures.Contains(f.name)) &&
s.Features.Count() == DesiredFeatures.Count()); // Incude Distinct in the comparison if Features list is not unique
Ensure that every Feature is DesiredFeature
Store contains all Desired features.
Code above assumes uniqueness in Features collection as well as DesiredFeatures, modify code as stated in comment line if this is not right
I have a string array with 5 items. How to get one of these 5 items by a linq query?
Code below returns only a boolean true.
string[] allWebTemplateSettings =SiteLidmaatschapSettings.Current.ProvisioningSettings;
var webTemplate = allWebTemplateSettings
.Select(x => x.StartsWith(string.Format("Template:{0}", web.WebTemplate)))
.FirstOrDefault();
Use Where instead of Select:
var webTemplate = allWebTemplateSettings.Where(x => x.StartsWith(string.Format("Template:{0}", web.WebTemplate))).FirstOrDefault();
Well, you're getting an IEnumerable of bools with your Select, then you pick the first one if there are any. That's why you're getting a bool as your answer.
I think what you actually want is this:
string[] allWebTemplateSettings = SiteLidmaatschapSettings.Current.ProvisioningSettings;
var prefix = string.Format("Template:{0}", web.WebTemplate);
var webTemplate = allWebTemplateSettings
.FirstOrDefault(x => x.StartsWith(prefix));
I've moved the string formatting operation out of the predicate since it is wasteful to recompute it for each element in your collection (especially if the collection is long).
You are confusing Select, which selects a new value based on each existing value of a sequence, with Where, which filters a sequence so it only contains items where a condition is met.
The simplest change is to replace your usage of Select with Where.
string[] allWebTemplateSettings = SiteLidmaatschapSettings.Current.ProvisioningSettings;
var webTemplate = allWebTemplateSettings
.Where(x => x.StartsWith(string.Format("Template:{0}", web.WebTemplate)))
.FirstOrDefault();
The other answers have rolled this usage of Where into FirstOrDefault without explaining your underlying confusion.
That's because StartsWith returns a bool and you're saying Select that bool based on whether it starts with that value or not. So actually, you're not even filtering on that value at all because you're not using a filter expression.
Actually, you only need FirstOrDefault as the list is already a List<string>
string[] allWebTemplateSettings = SiteLidmaatschapSettings.Current.ProvisioningSettings;
var webTemplate = allWebTemplateSettings
.FirstOrDefault(x => x.StartsWith(string.Format("Template:{0}", web.WebTemplate)));
Is this example bad practice because it make several database calls?
Is it any way I can make this to one DB call? Like use 'where' instead of 'firstOrDefault' and compare FlagDate with each date on the message in my messageList?
foreach (var message in messageList)
{
var dayFlag = db.DayFlags.FirstOrDefault(x =>
x.FlagDate == message.MessageDate);
}
If you want to retrieve only the dayFlags which a corresponding Date to the messageList, you need to extract the dates first in a separate list, then pass it to a Linq To Sql query.
Note that to retrieve only the first DayFlags of each Date, you need to group the flags by date.
var dates = messageList.Select(m => m.MessageDate).ToList();
var dayFlags = db.DayFlags.GroupBy(flag => flag.FlagDate)
.Where(group => dates.Contains(group.Key))
.Select(group => group.First());
This is a solution with linq:
var dates = messageList.Select(m => m.MessageDate).ToList();
var dayFlags = from df in db.DayFlags
where dates.Contains(df.FlagDate)
select df;
I'm sure that this can be easily done with Linq but I can't figure it out.
var ls1 = plotter.Model.Series.FirstOrDefault(x => x.IsSelected);
var ls2 = plotter.Model.Series.FirstOrDefault((x => x.IsSelected)&&(ls2!=ls1));
What I'm pretending to do is to obtain the two first objects that have their property IsSelected set to true.
I can't use the syntax written above because the compiler can't use "local variable ls2 before it is declared".
Use Where to filter only the selected results then use Take to select the first two e.g.
plotter.Model.Series.Where(x => x.IsSelected).Take(2);
Try this:
var ls1and2 = plotter.Model.Series.Where(x => x.IsSelected).Take(2);
var ls1 = plotter.Model.Series.Where(x => x.IsSelected).Take(2);
You should use the Take method and do this
var ls1 = plotter.Model.Series.Where(x => x.IsSelected).Take(2);