Reputation: 4610
I have a list of objects. I want to order by Date, and then by TransParentType and then by TransType. Then I want to group by TransParentType and within each group place a specific item (if it exists) at the bottom of the group (withdrawal: specific).
Sample Data:
Date TransParentType TransType
2015/05/20 Purchase investment
2015/05/20 Redemption withdrawal: b
2015/05/20 Redemption zz
2015/05/20 Redemption withdrawal: a
2015/05/20 Redemption withdrawal: specific
2015/05/20 Redemption withdrawal: c
2015/05/14 Purchase investment
Expected Sorted Data:
Date TransParentType TransType
2015/05/14 Purchase investment
2015/05/20 Purchase investment
2015/05/20 Redemption withdrawal: a
2015/05/20 Redemption withdrawal: b
2015/05/20 Redemption withdrawal: c
2015/05/20 Redemption withdrawal: specific
2015/05/20 Redemption zz
I'm trying to do something like this, without much success. The GroupBy does not maintain my sorted data. This is as far as i've gotten. Not sure if there is a way to move the specific item to the bottom of the group or if i have to do it manually...
results = results.OrderBy(r => r.Date).ThenBy(r=>r.TransParentType)
.ThenBy(r => r.TransType).ToList();
var grouped = results.GroupBy(g => g.TransParentType)...
Upvotes: 1
Views: 1092
Reputation: 60503
Well, I don't see the need of the group by from your Expected sorted Data.
I would do
results = results.OrderBy(r => r.Date)
.ThenBy(r=>r.TransParentType)
//just add an order criterion, checking if TransType == the value that you want at the end
//as order by a boolean returns false results first, this will put "widthdrawal: specific" at the end
//this will only make a difference for the elements starting with "withdrawal:"
.ThenBy(r => r.TransType == "widthdrawal: specific")
//finally, order TransType for all elements
.ThenBy(r => r.TransType)
.ToList();
EDIT :
With the new specifications given, I see something (ugly) like that
results = results
//order by date
.OrderBy(m => m.Date)
//order by transParentType
.ThenBy(m => m.TransParentType)
//order by the beginning of TransType (the part which may contain "withdrawal:"
.ThenBy(m => m.TransType.Substring(0, Math.Min(11, m.TransType.Length)))
.ThenBy(m => m.TransType == "withdrawal: specific")
.ThenBy(m => m.TransType);
Upvotes: 1
Reputation: 113382
The output you show in your question doesn't group at all, and is simply:
results.OrderBy(r => r.TransParentType).ThenBy(r => r.Date).ThenBy(r => r.TransType == "withdrawal: specific").ThenBy(r => r.TransType);
If I try your code, I find that the GroupBy does indeed maintain the order, except for obviously having it split into two separate groups.
If GroupBy
is indeed upsetting an order (though I can't see how) then you could use:
var groupedResults = results.GroupBy(r => r.TransParentType).Select(grp => grp.OrderBy(r => r.Date).ThenBy(r => r.TransType == "withdrawal: specific").ThenBy(r => r.TransType));
Which will give you an IEnumerable<OrderedEnumerable<>>
, so you can foreach
through each block and then foreach
through those in order again, and so on. (Or an IQueryable<IOrderedQueryable<>>
if done against a different linq source).
Upvotes: 0
Reputation: 8741
I believe something like this will work:
results = results
.OrderBy(r => r.Date)
.ThenBy(r => r.TransParentType)
.ThenBy(r => r.TransType == "withdrawal: specific" ? 1 : 0)
.ThenBy(r => r.TransType).ToList();
Upvotes: 1