Finding location in list, - c#

In Linq Get items higher then lastname I asked how to get people higher then a certain name.
However we use a datagrid with paging and when showing only people higher then lastname "Jan", there's no way to get back to people starting with AA.
So I was searching for a way to find out on what location the person would have been if following the normal order of selection?
hope this makes sense :)
[edit]
The query type is of EntityQuery.
[/edit]

So you want the index of first person record that matches your condition?
var index = query.TakeWhile(person => person.LastName.CompareTo(name) < 0).Count();
This counts the number of elements that match the condition and the returned value is the index of the first element that does not match with the condition.
Just note that you must negate the condition that you used with Where() as in this case TakeWhile() is used to get the items that you don't want.

Manage to solve this problem using the example given at
Getting to certain member using datapager and datagrid

Related

How do I obtain all the most recent elements from an IEnumerable?

I'm developing a Windows Forms application project for my university and we are using Entity Framework to store things.
It's an e-commerce type of program and now I'm struggling to find the right way to filter an IEnumerable based on the most recent ones.
What I want is to obtain all the elements from this table called prices, in which we also store older prices as a history backup.
This table has the ID of the article that refers to, the same for the corresponding prices list, a public, and a cost price, the updated date that is the moment it was created/updated.
I have tried using many expressions but ultimately failed miserably, sometimes I brought me only the ones within a certain price list or none at all or just one.
Again, I need it to work for a function that lets you update your prices based on parameters. For example, all articles and all price lists. For that, I want only the ones that are up to date so I won't touch the history of prices.
Example of what it should return:
Thank you very much!
Update: What I have tried didn't work, in fact, I couldn't even find sense in the code I wrote, that's why I didn't post it in the first place. I guess this problem ended my brain and I can't think properly anymore.
I tried some answers that I found here. For example:
// This is an IEnumerable of the price DTO class, which has the same properties as the table.
// It contains all the prices without a filter.
var prices= _priceService.Get();
// Attempt 1
var uptodatePrices= prices.GroupBy(x => x.ArticleId)
.Select(x => x.OrderByDescending(s => s.Date).FirstOrDefault());
// Attempt 2
uptodatePrices = prices.Select(x => new PriceDto
{
Date = prices.Where(z=> z.Id == x.Id).Max(g=>g.Date)
});
Ok, It sounds like you want to return the latest price for a combination of price list and article..
You're on the right path with your first attempt, but not quite there. The second attempt looks like pure frustration. :)
I believe the solution you will be looking for will be to group the products, then take the latest price for each group. To do that you need to use the values that identify your group as the group by expression, then sort the grouped results to take your desired one.
var uptodatePrices= prices.GroupBy(x => new { x.ArticloId, x.ListPrecioId} )
.Select(x => x.OrderByDescending(p => p.Date).First())
.ToList();
When you do a GroupBy, the value(s) you specify in the groupby expression become the "Key" of the result. The result also contains an IEnumerable representing the items from the original expression set (prices) that fit that group.
This selects the Price entity, you can change the Select to select a DTO/ViewModel to return, populated by the price instead as well.
In your case you were grouping by just the ArticloId, so you'd get back the latest entry for that Article, but not the combination of article and list price. In the above example I group by both article and list price, then tell it to Select from each group's set, take the latest Price record. I use First rather than FirstOrDefault as because I am grouping on combinations I know there will be at least 1 entry for each combination. (or else there would be no combination) Avoid using ...OrDefault unless you're sure, and are handling that no result may come back.
What you are working with are LINQ queries. If you only need to sort by most recent date, you can do that like this:
prices.OrderByDescending(price=>price.FechaActualizacion).ToList();
Make sure your Price model has the FechaActualizacion property.

Most efficient way to get item by name in Sitecore 7?

I have a Droplist field in an item that contains other items which are under the path /sitecore/content/Home. I need to get the selected item from the Droplist.
In this situation, I have to get the selected Item by its name. Are there any other efficient ways of doing this, or is the way I am doing this okay?
public static Item GetItemByName(string itemName)
{
Database masterDb = Factory.GetDatabase("master");
Item homeItem = masterDb.GetItem("/sitecore/content/Home");
return homeItem.Axes.GetDescendants().FirstOrDefault(p => p.Name == itemName);
}
Droplist is not the luckiest choice here. You should use Droplink instead - it stores the item as ID, instead of storing item name only.
You should avoid using name as item identifier. There can be multiple items with the same name, even under same parent.
homeItem.Axes.GetDescendants() is not really efficient method. It gets all the items which are under that node. You should avoid using it.
If you know that the item will be a child of the homeItem, you can use:
homeItem.Children.FirstOrDefault(p => p.Name == itemName)
If that item can be at any level under the homeItem, you can try to use index to get that item (checking item name equals to specified name and item full path starts with home page full path).
This more of an information note than the answer .. #Marek 's answer is absolutely correct that you should use a DropLink instead so that you address the ID of the item directly.
Never (never! Never!) use GetDescendants in a call such as this (ie from Home downwards).I would try and avoid using it anywhere, ever :) [If i could burn GetDescendants out of the API I would :P]
If you think about it, you are starting at the Home node and then iterating down, visiting every single item as you go and it wont stop until it has touched every item, pulled every item from the DB and interrogated it. On a small dev site this opertation will be fast but as your solution gets bigger and bigger, as content editors create more and more items you will find you solution gets slower and slower and your SQL Server get more and more load (and you likely wont immediately know why !)
If you need to do a larger ranging query (i.e. to check a field on every item under the home node) then you should look at Sitecore's ContentSearch API as this is massively faster for doing these sorts of operations.
As #Stephen Pope mentioned to most efficient way to search for an Item by Name is via the ContentSearch. I recently gave a simple Content Search example which you can modify for your needs by add the following line to so that it searches Sitecore Item Names to find those with a matching name.
IQueryable<SearchResultItem> query = index.GetQueryable<SearchResultItem>().Where(i => i.Name == itemName).Filter(predicate);
It is also worth following #Marek Musielak's advice and using Droplink over Droplist where possible so the value contained in the field is the ID of an Item instead of its Name which is far more useful in your development.
Most of them have given the answers correctly. I would also suggest the same.
Droplink is always preferable to droplist because it stores the item ID instead of name. Droplink will give you a lot of flexibility over droplist.
GetDescendants - Loop through all the items and check so avoid as much as possible.instead use sitecore queries or fast queries which gives you more efficiency.
masterDb.SelectItems("fast:/sitecore/content/Home//*[##templateid = '{F348C2A0-73B8-4AF4-BD9E-2C5901908369}']");
No one is going to store all the items in the same node. You would have created different type of items under home node. If you want to retrieve a specific set of items,Go for sitecore queries instead of getdescendants.

Linq query for ordering by ascending order except for one row

I am pulling data from a table like the example below:
status_id status_description
1 Unknown
2 Personal
3 Terminated
4 Relocated
6 Other
7 LOP
8 Continuing
I want to get the results into a IEnumerable which i am then returning to the front end to display the descriptions in a dropdown.
I want to sort this alphabetically and have the "Other" option always show up in the bottom of the dropdown.
Is there any way to get this in the backend? Currently I have this:
IEnumerable<employee_map> map= await(from emp in db.emp_status_map
orderby emp.status_description
select emp).ToListAsync();
Simply order on two values, first on whether the description is Other, then on the actual description itself:
orderby emp.status_description == "Other", emp.status_description
Servy's answer is fine, it works and fullfils your requirements. Another solution slightly different would be to add a field called "DisplayOrder", for example, and set it to 1 for all the rows except for "other", and set it to 2 (or whatever number you want) to "other". Then, you just order by DisplayOrder, Description.
It's highly probably that this solution is gonna be much faster if you define an index on DisplayOrder, Description.

Shortest way to bind a certain amout of items from a list to a data source?

Anyone know how to select a certain amount of items in a List to bind to a DataSource? Basically I'm getting back 10 items (which I don't have control over) and I only need to show 5. Originally I was thinking of using a loop and adding 5 items to a new list but that seems like a lot of code. Is there an expression that I can use to select the first 5?
//Returns a List<DataItem>
MyDataListControl.DataSource = Helper.GetDataItems(); //<= Possible expression?
You may take a look at the Skip and Take LINQ extension methods. So in your case if you wanted to take only the first 5 elements of some IEnumerable<T>:
MyDataListControl.DataSource = Helper.GetDataItems().Take(5).ToList();
What about List's GetRange method? Have you tried that? I don't the internal workings of the method; whether it also creates a new list or not.
GetRange(int index, int count)
Here is the msdn link for it.
RemoveRange will probably be best as you won't have to instanciate a new list, unless that happens internally anyway.. Just make sure you're always getting 10 items or you'll potentially get an ArgumentOutOfRangeException.
list.RemoveRange(5, 5);
That should leave you with the first five items.

How to get the last object in a generic list?

I am passing a populated SelectList to my View and I want to default the selected value to the last record in the list. So far I've got:
IQueryable<BuildNumber> projBuildNos = tcRepository.GetProjectBuildNos();
BuildList = new SelectList(projBuildNos, "ID", "value", projBuildNos.Last().ID);
I get an exception saying "the query operator 'Last' is not supported but I can't seem to get at the last record in my generic list and can't find any examples.
This code is from a 'form view model' passing select lists from my repository back to the view and I think I should be performing this here. However I'm new to generics/mvc/linq so am happy for alternative suggestions.
Thanks in advance for any help. Please let me know if you want any more info.
Are you already going to suck all the results from your query into memory? If so, I suggest you execute your query and get the result into a list:
List<BuildNumber> projBuildNos = tcRepository.GetProjectBuildNos().ToList();
BuildList = new SelectList(projBuildNos, "ID", "value", projBuildNos.Last().ID);
Otherwise you could easily end up with a workaround which executes the query twice - possibly giving inconsistent results.
I found this on MSDN:
Queryable.LastOrDefault -- Returns the last element in a sequence, or a default value if the sequence contains no elements.
Maybe this?
projBuildNos.Reverse().First().ID

Categories

Resources