Working with Lists, Anonymous Types and Suchlike
Following on from an earlier question, I now have a collection of an anonymous type
[User:
Username (as forename.surname
,
UserId
].
This collection of 'users' will ultimately need to be bound to a dropdown list. This is fine, but what I need to do is sort them by Surname and forename. but this is complicated by the fact that the username format is forename.surname.
At a high-level, this will involve a Split
on the string to separate the name components, then ToTitleCase()
both parts, then store the new values in another object within a List which I can then sort using List<T>.OrderBy(...).ThenBy(...)
It occurred to me that all this fancy new syntax I'm attempting to learn might include a way of performing this process in a couple of lines of terse code. Can anyone confirm or deny this?
Thanks.
EDIT 3:
I think I've cracked it:
var salesusers = (
from s in lstReport
group s by new { s.SalesUserId,s.Username}
into g
select new
{
Username = g.Key.Username.Split('.')[1].ToTitleCase() + " " + g.Key.Username.Split('.')[0].ToTitleCase(),
Surname = g.Key.Username.Split('.')[1].ToTitleCase(),
Forename = g.Key.Username.Split('.')[0].ToTitleCase(),
UserId = g.Key.SalesUserId
}
).OrderBy(a=> a.Surname).ThenBy(a=> a.Forename);
I need to create the separate forename and surname fields from the Username for sorting purposes and the Username for binding to a dropdownlist. It seems insane but it works so nicely I'm sticking with it for now. Would appreciate your comments.
EDIT2:
So I got as far as this. Now I'm wondering if the syntax will allow me to combine the Group by
operation from my earlier question with this step..
var sortedUsers = from u in salesusers
orderby u.UserName.Split('.')[1], u.UserName.Split('.')[0]
select new {UserName = u.UserName.Replace(".", " ").ToTitleCase(), UserId = u.UserId.Value};
Anybody ...?
EDIT: I managed to do it all most of it myself, in case anyone is ever needing, but converting the name components ToTitleCase
during the ordering operation is proving difficult.
This:
var sortedUsers = from u in salesusers
orderby u.UserName.Split('.')[1], u.UserName.Split('.')[0]
select u;
seems to do the trick everything I need apart from the ToTitleCase
ing. B开发者_如何学Cut of course there may be an even quicker/terser/more elegant method so I'll leave this open for a day or two to see what turns up ;-)
A little less code can be achieved using lambdas rather than expression syntax as so
var sorted = salesusers.OrderBy(u => u.UserName.Split('.')[1]).ThenBy(u => u.UserName.Split('.')[0]).ToList();
although it is less readable but once you are used to the syntax I find it easier than the expression syntax to read.
EDIT: changes for edit 3
Your code converted to Lambdas is as follows
var salesusers = (l.GroupBy(s => new { SalesUserId = s.SalesUserId, Username = s.Username }).Select(g =>new {
Username = g.Key.Username.Split('.')[1].ToTitleCase() + " " + g.Key.Username.Split('.')[0].ToTitleCase(),
Surname = g.Key.Username.Split('.')[1].ToTitleCase(),
Forename = g.Key.Username.Split('.')[0].ToTitleCase(),
UserId = g.Key.SalesUserId
})).OrderBy(a => a.Surname).ThenBy(a => a.Forename);
The only thing is that the bigger the expression gets the harder it gets to read!
Another way you could do it which reads cleaner is to define the details object rather than using a dynamic object.
internal class UserDetails
{
public UserDetails(User u)
{
this.Forename = u.Username.Split('.')[0].ToTitleCase();
this.Surname = u.Username.Split('.')[1].ToTitleCase();
this.UserId = u.SalesUserId;
this.Username = u.Username;
}
public string Username { get; set; }
public string Surname { get; set; }
public string Forename { get; set; }
public int UserId { get; set; }
}
then you can do
var salesusers = (l.GroupBy(s => new { SalesUserId = s.SalesUserId, Username = s.Username })
.OrderBy(u => u.Username.Split('.')[1].ToTitleCase())
.ThenBy(u => u.Username.Split('.')[0].ToTitleCase())
.Select(g => new UserDetails(g)));
but this is more code which I'm not sure you want.
LATEST EDITS:
your Code doesn't require the group by statement so you could reduce that by doing
var salesusers = (
from s in l
select new
{
Username = s.Username.Split('.')[1].ToTitleCase() + " " + s.Username.Split('.')[0].ToTitleCase(),
Surname = s.Username.Split('.')[1].ToTitleCase(),
Forename = s.Username.Split('.')[0].ToTitleCase(),
UserId = s.SalesUserId
}
).OrderBy(a => a.Surname).ThenBy(a => a.Forename);
Or using Lambdas becomes
var salesusers = l.Select(g =>new {
Username = g.Username.Split('.')[1].ToTitleCase() + " " + g.Username.Split('.')[0].ToTitleCase(),
Surname = g.Username.Split('.')[1].ToTitleCase(),
Forename = g.Username.Split('.')[0].ToTitleCase(),
UserId = g.SalesUserId
}).OrderBy(a => a.Surname).ThenBy(a => a.Forename);
Other than that the only way I can see to reduce that call further is with a defined class as above, thats not to say it can't be done! but I can't see how!
HTH
OneShot
Here's the final solution I came up with - it sorts, ToTitleCase
s and formats. Rather nifty if I say so myself. Took me all morning tho :-(
var salesusers = (
from s in lstReport
group s by new { s.SalesUserId,s.Username}
into g
select new
{
Username = g.Key.Username.Split('.')[1].ToTitleCase() + " " + g.Key.Username.Split('.')[0].ToTitleCase(),
Surname = g.Key.Username.Split('.')[1].ToTitleCase(),
Forename = g.Key.Username.Split('.')[0].ToTitleCase(),
UserId = g.Key.SalesUserId
}
).OrderBy(a=> a.Surname).ThenBy(a=> a.Forename);
精彩评论