I want to sort properties based off an attribute parameter Order that is given.
Attribute:
public class Items: Attribute
{
public int Order { get; set; }
public Items(int order)
{
this.Order = order;
}
}
Implementation:
public class client
{
[Items(1)]
public string fName {get; set;}
[Items(3)]
public string lName {get; set;}
[Items(2)]
public string mName {get; set;}
}
Get all Properties:
var properties = typeof(client).GetProperties().Where(
prop => prop.IsDefined(typeof(Items), false));
Sort by Order#?
This is what I tried but it does not work
Array.Sort(properties, delegate (Items x, Items y)
{ return x.Order.CompareTo(y.Order); });
How do I sort the properties based off the Order?
This has been solved, but would like to extend the question.
Is there a way to sort properties without having to put an "Order" on them. I am wanting to just have an attribute "EndOfList" Or "Last" that would state be sure to sort these last. So that I would not have to clutter up the code with Orders.
You can use Linq and OrderBy
var sorted = properties
.OrderBy(p => ((Items)p.GetCustomAttributes(true)
.FirstOrDefault(a => a is Items)).Order);
This results in following order: fName, mName, lName.
So what happens inside the OrderBy: access custom properties. Find a first that is of type Items and use the Order property as a sort parameter.
To sort in reversed order just use OrderByDescending.
You can try this
var properties = typeof(client).GetProperties().Where(prop => prop.IsDefined(typeof(Items), false));
var sortedProperties = properties.OrderBy(x => ((Items)x.GetCustomAttributes(typeof(Items), false).FirstOrDefault()).Order);
Related
Any idea why the LINQ OrderBy is not working in following code, (have no errors but method does not sort ...)
First my own type
public class IQLinksView
{
public int id { get; set; }
public int catid { get; set; }
public int? viewed {get;set;}
public string name {get;set;}
public string desc {get;set;}
public string url {get;set;}
public string pic {get;set;}
public string cat {get;set;}
}
then query :
IQueryable<IQLinksView> newView =
from links in this.emContext.tbl_otherlinks
select new IQLinksView { id = links.pklinkid, catid =
links.tbl_catgeory.pkcategoryid, viewed = links.linkviewed, name = links.linkname,
desc = links.linkdesc, pic = links.linkpicture, url = links.linkurl, cat =
links.tbl_catgeory.categoryname };
Untill here all fine :-), but then
newView.OrderBy(x => x.viewed);
just changes nothing,... Page is loading results showing ... but no ordering ... sniff
i have Try with (creating a comparer object ... ):
newView.OrderBy(x => (Int32)x.viewed, new CompareIntegers());
same result, no ordering ...
I do have workarounds but just wondering what is missing ....
Any suggestions will be appreciated thanks a lot :-)
Don't throw away the return value. The OrderBy extension method is does not mutate the input. Try:
newView = newView.OrderBy(x => x.viewed);
There is no reason why that won't work, assuming the viewed value is correct. Also, make sure that OrderBy is after any operations (e.g. Distinct) which will ruin ordering.
Happy coding!
No-Tracking Queries
Consider use the asnotracking() after orderby() if the result is a readonly result.
Example:
query = query.OrderByDescending(x => x.Rating).AsNoTracking();
I have the following basic classes (cut down for this question):
public class Parent
{
public string Name { get; set; }
public IList<Child> Children { get; set; }
}
public class Child
{
public string Name { get; set; }
}
If I have a Parent collection, what I'd like to do is get an IList that is sorted by Parent.Name and also the Children for each parent need to be sorted by their Name.
I've tried this (which only sorts the Parents, not the Children):
IList<Parent> parents = ... //Populated
parents.OrderBy(p => p.Name).ThenBy(p => p.Children.OrderBy(c => c.Name)).ToList()
I've searched but can't find anything (probably me being dumb).
Any suggestions for a Linq newbie?
Thanks in advance
Andy
First of all, calling OrderBy on the list, the way you do, won't sort it in-place. It will return a new sorted IEnumerable; you can use .ToList() on that to turn it into a list, but it will still be a copy. Now on to the sorting itself. You really need to not just order the items in the collection, but make a copy of each item which would have its Children sorted as well. So:
IList<Parent> parents = ... //Populated
parents = (from p in parents
orderby p.Name
select new Parent
{
Name = p.Name,
Children = p.Children.OrderBy(c => c.Name).ToList()
}
).ToList();
Same solution, using LINQ method syntax:
IList<MyType> myTypeList = ... //Populated
var sortedList = myTypeList.Select(t =>
{
t.Children = t.Children.OrderBy(c => c.Name).ToList();
return t;
}).ToList();
I have a c# app. I have custom list of type result, shown below. The list is called 'myResultList'.
enumResult { noResult = 0, win = 1, lose = 2 }
class Result
{
public enumResult OutCome {get; set;}
public double Frequency {get;set;}
public string GroupName {get; set;}
public double TotalValue {get; set;}
}
myResultList contains numerous elements. I wish to select all the elements where the Outcome equals lose into a new list. I believe LINQ is probably best for this task, correct me if I am wrong. How do I go about querying a list based on a enumeration?
var lostResults = myResultList.Where(r => r.OutCome == enumResult.lose).ToList();
NOTE: Consider to have Pascal Case names for types and public members. And don't include prefixes in type names. E.g.
public enum Outcome
{
NoResult,
Win,
Lose
}
If you will need to filter results by other types of outcomes, then consider to use lookup:
var results = myResultList.ToLookup(r => r.OutCome);
Then getting results by their type will be easy:
var wonResults = results[enumResult.won];
var newList = myResultList.Where(r => r.OutCome == enumResult.lose).ToList();
I have a BindingList with objects in which is saved some contacts.
internal static BindingList<object> contactList;
The contactList object is more types. SktContact, FBContact, GContact.
These contacts I add in contactList_Changed event to listBox. But I want sort them by status (first online) and then alphabetically.
I would like somethink like this:
List<object> contactSorted = new List<object>();
contactSorted = Global.contactList.ToList();
contactSorted.OrderBy((status, name) => Converter.getContactAvailabilityStatus(contactSorted[?]), Converter.getContactName(contactSorted[?]));
contactListBox.Items.AddRange(contactSorted.ToArray());
But I dont have any idea how shoud I do that. I cannot retype the list of objects and select the property to order by.
I have methods to get status and name from any object. But how can I use it to sort the contact array?
I'm using own drawing Owner draw fixed
private void contactListBox_DrawItem(object sender, DrawItemEventArgs e)
It feels like you could use an interface for the contact type:
interface IContact
{
string Status { get; }
string Name { get; }
}
class FBContact : IContact
{
public string Status
{
get
{
// Implement the status getter
}
}
public string Name
{
get
{
// Implement the contact name getter
}
}
}
Then just
var unsortedList = Global.contactList;
var contactSorted = unsortedList.Cast<IContact>()
.OrderBy(x => x.Status)
.ThenBy(x => x.Name);
contactListBox.Items.AddRange(contactSorted.ToArray());
What you can do is to implement an interface for your contact classes.
public interface IContact{
string Name {get;set;}
int Status{get;set;}
}
And change your class declarations as
public class SktContact: IContact {
// Implementations
}
...
After that you can declare your list with the interface name
var contacts= new List<IContact>():
// Populate contacts to the list
Then order the list as
var orderedList = contact.OrderByDescending(c=>c.Status).ThenBy(c=>c.name).ToList():
Then while using the list items you can use GetType() method to determine their types and use the appropriate code to handle them.
In case if you don't have access to the implementations of the contact classes you can use Adapter Design Pattern to make them compatible with your code.
I am trying to apply a bit of groupby/crosstabbing logic to an IEnumerable list of a user defined object and was wondering if anyone could help me out. I'm stuck with an existing (rather annoying) object model to work with but anyway here goes...
consider the following class which I will condense to only relevant properties so you get the jist...
public class Holding
{
private void Institution;
private string Designation;
private Owner Owner;
private Event Event;
private Shares Shares;
}
I want to convert this into a list that satifys the following...
The object is grouped by Institution.
This parent list of institutions contains a list of a new object with a unique combination of Designation and Owner.
Now for each of this combination of Designation and Owner we get another child list of unique Events.
So it basically 3 lists deep.
I'm not sure if this is possible with an IEnumerable List or not, I have toyed around quite a bit with the GroupBy extension method to no avail thus far. I'd like most to do it this way, but I'm using linq-to-sql to get the initial list of holdings which is as follows and might be the better place to do the business...
public static List<Holding> GetHoldingsByEvents(
int eventId1,
int eventId2)
{
DataClassesDataContext db = new DataClassesDataContext();
var q = from h in db.Holdings
where
h.EventId == eventId1 ||
h.EventId == eventId2
select h;
return q.Distinct().ToList();
}
Any help/guidance would be much appreciated...
Thanks in advance.
I'm using ToLookup method, which is kind of a grouping, it takes two parameters, first one a function used for defining the group keys and the next one is a function used as a selector (what to take from the match).
items.ToLookup(c=>c.Institution.InstitutionId, c => new {c.Designation, c.Owner, c.Event})
.Select(c => new {
// find the institution using the original Holding list
Institution = items.First(i=>i.Institution.InstitutionId == c.Key).Institution,
// create a new property which will hold the groupings by Designation and Onwner
DesignationOwner =
// group (Designation, Owner, Event) of each Institution by Designation and Owner; Select Event as the grouping result
c.ToLookup(_do => new {_do.Designation, _do.Owner.OwnerId}, _do => _do.Event)
.Select(e => new {
// create a new Property Designation, from e.Key
Designation = e.Key.Designation,
// find the Owner from the upper group ( you can use items as well, just be carreful this is about object and will get the first match in list)
Owner = c.First(o => o.Owner.OwnerId == e.Key.OwnerId).Owner,
// select the grouped events // want Distinct? call Distinct
Events = e.Select(ev=>ev)//.Distinct()
})
})
I assumed your classes look like these
public class Holding
{
public Institution Institution {get; set;}
public string Designation {get; set;}
public Owner Owner {get; set;}
public Event Event {get; set;}
}
public class Owner
{
public int OwnerId {get; set;}
}
public class Event
{
public int EventId {get; set;}
}
public class Institution
{
public int InstitutionId {get; set;}
}