I'm having a strange issue trying to order a list based on whether or not it contains a particular string value. Within a view, I have a list on my viewmodel for which I would like to display those objects which are not "snoozed" first and then ordered by whether or not their title contains the word "order". So my code is as follows:
var sortedFaults = accountFaultContainer.Faults.Values.OrderBy(f => f.IsSnoozed).ThenByDescending(f => f.Title.ToLower().Contains("order"));
I then loop through this list and add the 'faults' to my table using a foreach loop...
foreach (Fault fault in sortedFaults)
This works in some cases but not in others. I've been trying to single out those that do not behave as expected but there is no clear difference. For example, in once case, a title of "Full failing sync" was ordered both before and after "Failing order syncs". But it is not the case that this always misbehaves; in some tables the ordering is working.
Has anybody come across a similar issue before? Or is there something blatantly obvious I'm missing? I'm scratching my head here!
You order by IsSnoozed first, so that takes priority.
.OrderBy(f => f.IsSnoozed)
.ThenByDescending(f => f.Title.ToLower().Contains("order"));
Try it the other way around:
.OrderBy(f => f.Title.ToLower().Contains("order"))
.ThenByDescending(f => f.IsSnoozed);
Related
So, I currently have a LINQ query
BStops.JPPlatforms.Platform
.Where(Stop => Stop.Name.ToLower().Contains(SearchBox.Text.ToLower()))
.Select(Stop => new { Stop.Name, Stop.PlatformNo })
.ToList();
Which is returning the data I expect it to, the property Platform contains a list of stops that hold another class with properties I want to access to such as Name, PlatformNo and PlatforTag, now the killer for me is two things, one is less important at the moment but if you can help it would be great!
So I want to format this output so when you search it doesn't have all this garbled stuff around it, I would prefer it to be like
Annex Rd near Railway (50643)
I've tried adjusting my query to be like
BStops.JPPlatforms.Platform
.Where(Stop => Stop.Name.ToLower().ToString().Contains(SearchBox.Text.ToLower().ToString()))
.Select(Stop => String.Format("{0} ({1})",new { Stop.Name, Stop.PlatformNo }))
.ToList();
But that causes it to crash back to a unhanded exception, for the life of me I can't seem to figure this out, as for the second part. I'd also like my LINQ query to search both the Name and PlatformNo properties I've already tried the logical || but it crashes back to an unhanded exception and I don't know enough about LINQ to figure out why, any help at this point would be great :).
Changing your LINQ query to this would solve the problem.
BStops.JPPlatforms.Platform.Where(Stop => Stop.Name.ToLower()
.Contains(SearchBox.Text.ToLower()))
.Select(Stop => new
{
StopAddress = $"{Stop.Name} {Stop.PlatformNo}"
})
.ToList();
The Where clause is not performant. The Text.ToLower should be done outside of the Linq. Also ToLower returns a string, so there is no need go call ToString
The Select should not create a new object.
var text = SearchBox.Text.ToLower();
BStops.JPPlatforms.Platform
.Where(stop => stop.Name.ToLower().Contains(text))
.Select(stop => String.Format("{0} ({1})", stop.Name, stop.PlatformNo))
.ToList();
I have a database of strings that contain IDs. I need to pass that list into a LINQ query so I can pull the correct records.
model.SelectedDealers = db.dealers.Any(a => a.sdealer_name.Contains(UserToEdit.UserViewAccesses.Select(s => s.ViewReferenceNumber)));
SelectedDealers is of type dealers
ViewReferenceNumber should be a list of strings which should match sdealer_name
So essentially I am trying to find all of the dealers whos sdealer_name matches the list of sdealer_names I have in my UserToEdit.UserViewAccesses
I've tried moving parts around and switching them in different spots and can't seem to figure this out.
Any() is just a boolean indicating if there are any results. It doesn't actually return the results.
If I understand what you are after correctly, then this might work:
var dealerNames = UserToEdit.UserViewAccesses.Select(s => s.ViewReferenceNumber).ToList();
model.SelectedDealers = db.dealers.Where(a => dealerNames.Contains(a.sdealer_name));
So essentially I am trying to find all of the dealers whos
sdealer_name matches the list of sdealer_names I have in my
UserToEdit.UserViewAccesses
var dealersthatmatched = (from d in UserToEdit.UserViewAccesses.sdealer_names
where d == sdealer_name
select d).ToList()
Wish I could have made a comment instead, but as I don't have enough rep I can't. I wish I understood the requirement better, but you seem ready and able to try stuff so perhaps you find this useful.
Here is what my model looks like:
I'm trying to get the count of distinct Assesors by a certain EventId.
Here's the code I'm trying to use:
var x = db.Assessors.Select(a => (a.Assessments.Select(y => y.EventFacility.EventId == 138))).Count();
Unfortunately, I must be coding this wrong because instead of getting the expected result (a count of 9, in this case) I'm getting the wrong result: 35.
I'm wondering if someone can take a look at my LINQ statement and tell me what I'm doing wrong?
You need to use Where and Any like this:
var result = db.Assessors
.Where(a => a.Assessments.Any(y => y.EventFacility.EventId == 138));
What this is saying is that you want all Assessors that are parents of any Assessment that is related to that particular Event.
You're going about this backward, start from what you know (the event since you have it's ID) and navigate to what you want through the navigation properties.
It's impossible to tell from your schema as it includes neither the properties nor the mapping type 1:1? 1:N? Can't know from simple lines
It would probably look Something like this
var x = db.Events
.Where(ev=>ev.Id == 138)
.SelectMany(ev=>ev.EventFacilities) //(i'm assumine possibly multiple and not 1 per event, once again schema doesn't show it, if it's not the case change SelectMany to Select)
.SelectMany(ef=>ef.Assesments) // Same assumption as above
.Select(as=>as.Assessor) // Asuming otherwise here, if wrong change Select to SelectMany
.Distinct(); // Ignore duplicate assessors
Note that your question is impossible to answer as is, this is a best effort but if you want help you should give "all" the information required, not strip out what doesn't immediately seem relevant, it would've been much easier if you took an actual screenshot of your entity diagram instead of what you made up.
From what I understand, this seems to not be a safe practice...
I have a foreach loop on my list object that I am stepping through. Inside that foreach loop I am looking up records by an Id. Once I have that new list of records returned by that Id I do some parsing and add them to a new list.
What I would like to do is not step through the same Id more than once. So my thought process would be to remove it from the original list. However, this causes an error... and I understand why.
My question is... Is there a safe way to go about this? or should I restructure my thought process a bit? I was wondering if anyone had any experience or thoughts on how to solve this issue?
Here is a little pseudocode:
_myList.ForEach(x =>
{
List<MyModel> newMyList = _myList.FindAll(y => y.SomeId == x.SomeId).ToList();
//Here is where I would do some work with newMyList
//Now I am done... time to remove all records with x.SomeId
_myList.RemoveAll(y => y.SomeId == x.SomeId);
});
I know that _myList.RemoveAll(y => y.SomeId == x.SomeId); is wrong, but in theory that would kinda be what I would be looking for.
I have also toyed around with the idea of pushing the used SomeId to an idList and then have it check each time, but that seems cumbersome and was wondering if there was a nicer way to handle what I am looking to do.
Sorry if i didnt explain this that well. If there are any questions, please feel free to comment and I will answer/make edits where needed.
First off, using ForEach in your example isn't a great idea for these reasons.
You're right to think there are performance downsides to iterating through the full list for each remaining SomeId, but even making the list smaller every time would still require another full iteration of that subset (if it even worked).
As was pointed out in the comments, GroupBy on SomeId organizes the elements into groupings for you, and allows you to efficiently step through each subset for a given SomeId, like so:
_myList.GroupBy(x => x.SomeId)
.Select(g => DoSomethingWithGroupedElements(g));
Jon Skeet has an excellent set of articles about how the Linq extensions could be implemented. I highly recommend checking it out for a better understanding of why this would be more efficient.
First of all, a list inside a foreach is immutable, you can't add or delete content, nor rewrite an element. There are a few ways you could handle this situation:
GroupBy
This is the method I would use. You can group your list by the property you want, and iterate through the IGrouping formed this way
var groups = list.GroupBy(x => x.yourProperty);
foreach(var group in groups)
{
//your code
}
Distinct properties list
You could also save properties in another list, and cycle through that list instead of the original one
var propsList = list.Select(x=>x.yourProperty).Distinct();
foreach(var prop in propsList)
{
var tmpList = list.Where(x=>x.yourProperty == prop);
//your code
}
While loop
This will actually do what you originally wanted, but performances may not be optimal
while(list.Any())
{
var prop = list.First().yourProperty;
var tmpList = list.Where(x=>x.yourProperty == prop);
//your code
list.RemoveAll(x=>x.yourProperty == prop);
}
I have two IList<CustomObject>, where CustomObject has a Name property that's a string. Call the first one set, and the second one subset. set contains a list of things that I just displayed to the user in a multiselect list box. The ones the user selected have been placed in subset (so subset is guaranteed to be a subset of set, hence the clever names ;) )
What is the most straightforward way to generate a third IList<CustomObject>, inverseSubset, containing all the CustomObjects the user DIDN'T select, from these two sets?
I've been trying LINQ things like this
IEnumerable<CustomObject> inverseSubset = set.Select<CustomObject,CustomObject>(
sp => !subset.ConvertAll<string>(p => p.Name).Contains(sp.Name));
...based on answers to vaguely similar questions, but so far nothing is even compiling, much less working :P
Use the LINQ Except for this:
Produces the set difference of two sequences.
Aha, too much SQL recently - I didn't want Select, I wanted Where:
List<string> subsetNames = subset.ConvertAll<string>(p => p.Name);
IEnumerable<CustomObject> inverseSubset =
set.Where<CustomObject>(p => !subsetNames.Contains(p.Name));