Sorting a composite collection - c#

So WPF doesn't support standard sorting or filtering behavior for views of CompositeCollections, so what would be a best practice for solving this problem.
There are two or more object collections of different types. You want to combine them into a single sortable and filterable collection (withing having to manually implement sort or filter).
One of the approaches I've considered is to create a new object collection with only a few core properties, including the ones that I would want the collection sorted on, and an object instance of each type.
class MyCompositeObject
{
enum ObjectType;
DateTime CreatedDate;
string SomeAttribute;
myObjectType1 Obj1;
myObjectType2 Obj2;
{
class MyCompositeObjects : List<MyCompositeObject> { }
And then loop through my two object collections to build the new composite collection. Obviously this is a bit of a brute force method, but it would work. I'd get all the default view sorting and filtering behavior on my new composite object collection, and I'd be able to put a data template on it to display my list items properly depending on which type is actually stored in that composite item.
What suggestions are there for doing this in a more elegant way?

I'm not yet very familiar with WPF but I see this as a question about sorting and filtering List<T> collections.
(withing having to manually implement sort or filter)
Would you reconsider implementing your own sort or filter functions? In my experience it is easy to use. The examples below use an anonymous delegate but you could easily define your own method or a class to implement a complex sort or filter. Such a class could even have properties to configure and change the sort and filter dynamically.
Use List<T>.Sort(Comparison<T> comparison) with your custom compare function:
// Sort according to the value of SomeAttribute
List<MyCompositeObject> myList = ...;
myList.Sort(delegate(MyCompositeObject a, MyCompositeObject b)
{
// return -1 if a < b
// return 0 if a == b
// return 1 if a > b
return a.SomeAttribute.CompareTo(b.SomeAttribute);
};
A similar approach for getting a sub-collection of items from the list.
Use List<T>.FindAll(Predicate<T> match) with your custom filter function:
// Select all objects where myObjectType1 and myObjectType2 are not null
myList.FindAll(delegate(MyCompositeObject a)
{
// return true to include 'a' in the sub-collection
return (a.myObjectType1 != null) && (a.myObjectType2 != null);
}

"Brute force" method you mention is actually ideal solution. Mind you, all objects are in RAM, there is no I/O bottleneck, so you can pretty much sort and filter millions of objects in less than a second on any modern computer.
The most elegant way to work with collections is System.Linq namespace in .NET 3.5
Thanks - I also considered LINQ to
objects, but my concern there is loss
of flexibility for typed data
templates, which I need to display the
objects in my list.
If you can't predict at this moment how people will sort and filter your object collection, then you should look at System.Linq.Expressions namespace to build your lambda expressions on demand during runtime (first you let user to build expression, then compile, run and at the end you use reflection namespace to enumerate through results). It's more tricky to wrap your head around it but invaluable feature, probably (to me definitively) even more ground-breaking feature than LINQ itself.

Update: I found a much more elegant solution:
class MyCompositeObject
{
DateTime CreatedDate;
string SomeAttribute;
Object Obj1;
{
class MyCompositeObjects : List<MyCompositeObject> { }
I found that due to reflection, the specific type stored in Obj1 is resolved at runtime and the type specific DataTemplate is applied as expected!

Related

Utilisation of a Dictionary like class

For the purpose of XML serialisation I had to disband a Dictionary collection I was using. I wrote a very straightforward alternative which consists of 2 classes:
NameValueItem: contains Name (Key) and Value
NameValueCollection: derived from CollectionBase and maintains a collection of NameValueItem objects.
I've included some standard methods to help maintain the collection (Add, Contains and Remove). So just like most Dictionary types, the Name (or Key) is unique:
public bool Contains(NameValueItem item)
{
foreach (NameValueItem lItem in List)
if(lItem.Name.Equals(item.Name))
return true;
return false;
}
Add uses this Contains method to determine whether to include a given item into the collection:
public void Add(NameValueItem item)
{
if (!Contains(item))
List.Add(item);
}
As bog standard, straightforward and easy as this code appears it's proving to be a little sluggish. Is there anything that can be done to improve the performance of this? Or alternatives I could use?
I was considering creating a NameValueHashSet, which is derived from HashSet.
Optional...:
I had a question which I was going to ask in a separate thread, but I'll leave it up to you as to whether you'd like to address it or not.
I wanted to add 2 properties to the NameValueCollection, Names and Values, which return a List of strings from the Collection of NameValueItem objects. Instead I built them into methods GetNames() and GetValues(), as I have to build the collection (i.e. create a List (names/values), iterate over collection adding names/value to List and return List).
Is this a better alternative? In terms of good coding practise, performance, etc.? As my thoughts regarding properties has always been to have it as stripped back as possible, that only references, arithmetic, etc. should exist, with no layers of processes. If that is the case, then it should be built into a method. Thoughts?
Perhaps you shouldn't try to rebuild what the framework already provides? Your implementation of a dictionary is going to perform poorly as it does not scale. The built in Dictionary<TKey, TValue> has O(1) access performance and for most insert and delete operations (unless there are collisions or the internal storage must be expanded).
You can extend the existing dictionary to provide XML serialization support; see this question and answers: Serialize Class containing Dictionary member
As for your second question - Dictionary already provides methods for getting an IEnumerable of the keys and values. This enumerates the keys and/or values as requested by the caller; that is delayed execution and is likely the preferred method over building a full List every time (which requires iterating through all the elements in the dictionary). If the caller wants a list then they just do dictionary.Values.ToList().

Best way to access attributes

I am working on a framework that uses some Attribute markup. This will be used in an MVC project and will occur roughly every time I view a specific record in a view (eg /Details/5)
I was wondering if there is a better/more efficient way to do this or a good best practices example.
At any rate, I have an a couple of attributes e.g:
[Foo("someValueHere")]
String Name {get;set;}
[Bar("SomeOtherValue"]
String Address {get;set;}
What is the most efficient way/best practice to look for these attributes/Act on their values?
I am currently doing something like this:
[System.AttributeUsage(AttributeTargets.Property)]
class FooAttribute : Attribute
{
public string Target { get; set; }
public FooAttribute(string target)
{
Target = target;
}
}
And in my method where I act on these attributes(simplified example!):
public static void DoSomething(object source)
{
//is it faster if I make this a generic function and get the tpe from T?
Type sourceType = source.GetType();
//get all of the properties marked up with a foo attribute
var fooProperties = sourceType
.GetProperties()
.Where(p => p.GetCustomAttributes(typeof(FooAttribute), true)
.Any())
.ToList();
//go through each fooproperty and try to get the value set
foreach (var prop in fooProperties)
{
object value = prop.GetValue(source, null);
// do something with the value
prop.SetValue(source, my-modified-value, null);
}
}
Attribute.GetCustomAttribute and PropertyInfo/MemberInfo.GetCustomAttribute is the recommended way of getting at attribute objects.
Although, I wouldn't normally enumerate all properties with attributes; you generally want to work a particular attribute so you'd just call GetCustomAttribute directly.If you're looking for attributes on any of your properties, enumerating those properties looking for attributes based on GetCustomAttribute() the way you're doing it, is the best way to do it.
There is not really much choice when dealing with attributes - your code is ok and reasonable as is, it is also unlikley to be your main performance concern. The only immediate thing is to drop ToList call as absolutely unnecessary.
Side notes: performance related question should look approximately
"I've measured my code and portion XXX seems to be taking too much time (YYY) . The time goal for this piece of code is ZZZ. Is my way of doing XXX reasonable/where can I improve it?".
Note that in you case you are missing YYY and ZZZ time portions - so you can't really say if it is slow for your case or not. And you may want to start measurements with DB/other IO bound operations as it more likely to speed up your overall code.
After you figured that this attribute related code is main perfomance issue you can consider some sort of caching of results or even code generation of some sort (either through caching lambdas that would set necessary values or even full blown IL generation).

Generate and compile name to index translation/mapping for faster reusability

Suppose I get data from a service (that I can't control) as:
public class Data
{
// an array of column names
public string[] ColumnNames { get; set; }
// an array of rows that contain arrays of strings as column values
public string[][] Rows { get; get; }
}
and on the middle tier I would like to map/translate this to an IEnumerable<Entity> where column names in Data may be represented as properties in my Entity class. I said may because I may not need all the data returned by the service but just some of it.
Transformation
This is an abstraction of an algorithm that would do the translation:
create an IDictionary<string, int> of ColumnNames so I can easily map individual column names to array indices in individual rows.
use reflection to examine my Entity properties' names so I'm able to match them with column names
iterate through Data.Rows and create my Entity objects and populate properties according to mapping done in #1. Likely using reflection and SetValue on properties to set them.
Optimisation
Upper algorithm would of course work, but I think that because it uses reflection it should do some caching and possibly some on the fly compilation, that could speed things up considerably.
When steps 1 and 2 are done, we could actually generate a method that takes an array of strings and instantiates my entities using indices directly and compile it and cache it for future reuse.
I'm usually getting a page of results, so subsequent requests would reuse the same compiled method.
Additional fact
This is not imperative to the question (and answers) but I also created two attributes that help with column-to-property mapping when these don't match in names. I created the most obvious MapNameAttribute (that takes a string and optionally also enable case sensitivity) and IgnoreMappingAttribute for properties on my Entity that shouldn't map to any data. But these attributes are read in step 2 of the upper algorithm so property names are collected and renamed according to this declarative metadata so they match column names.
Question
What is the best and easiest way to generate and compile such a method? Lambda expressions? CSharpCodeProvider class?
Do you maybe have an example of generated and compiled code that does a similar thing? I guess that mappings are a rather common scenario.
Note: In the meantime I will be examining PetaPoco (and maybe also Massive) because afaik they both do compilation and caching on the fly exactly for mapping purposes.
Suggestion: obtain FastMember from NuGet
Then just use:
var accessor = TypeAccessor.Create(typeof(Entity));
Then just in your loop, when you have found the memberName and newValue for the current iteration:
accessor[obj, memberName] = newValue;
This is designed to do what you are asking; internally, it maintains a set of types if has seen before. When a new type is seen, it creates a new subclass of TypeAccessor on-the-fly (via TypeBuilder) and caches it. Each unique TypeAccessor is aware of the properties for that type, and basically just acts like a:
switch(memberName) {
case "Foo": obj.Foo = (int)newValue;
case "Bar": obj.Bar = (string)newValue;
// etc
}
Because this is cached, you only pay any cost (and not really a big cost) the first time it ever sees your type; the rest of the time, it is free. Because it uses ILGenerator directly, it also avoids any unnecessary abstraction, for example via Expression or CodeDom, so it is about as fast as it can be.
(I should also clarify that for dynamic types, i.e. types that implement IDynamicMetaObjectProvider, it can use a single instance to support every object).
Additional:
What you could do is: take the existing FastMember code, and edit it to process MapNameAttribute and IgnoreMappingAttribute during WriteGetter and WriteSetter; then all the voodoo happens on your data names, rather than the member names.
This would mean changing the lines:
il.Emit(OpCodes.Ldstr, prop.Name);
and
il.Emit(OpCodes.Ldstr, field.Name);
in both WriteGetter and WriteSetter, and doing a continue at the start of the foreach loops if it should be ignored.

c# in memory query of objects without linq

We are still using .Net Framework 2.0 / VS 2005 so i do not have LINQ. If i don't want to go with the poor man's LINQ solution, what are some other alternatives for being able to query in memory custom objects in a dictionary?
I'm not sure if one of your poor man's LINQ solution is LINQBridge but I used it for a few weeks and it seemed to be working okay before we actually switched to .NET 3.5 and the real deal.
Dictionary<T> would seem like a good choice, although you haven't provided much information about what you mean by "query." Are you just looking to retrieve data based on some key value? Get a count of total items? Do a sum or average based on some condition? You really need to give more information to get a better answer.
To elaborate on what Chesso said, you'll have to iterate the loop just like LINQ does...
for example:
static T FindFirst<T>(IEnumerable<T> col, Predicate<T> predicate)
{
foreach(T t in col)
{
if(predicate(t))
{
return t;
}
}
return default(T);
}
I was not aware of the Predicate delegate, that seems to be pretty much what i was looking for. As far as the context for which i'm querying:
Say i have a object X with properties A (name, guaranteed to be unique) and B (age)
1) I have a series of objects in a dictionary whose keys are say Property A of a given object, and of course the value is the object iself.
Now i want to retrieve all objects in this dictionary which meet a certain criteria of B, say age > 20.
I can add all the values of the dictionary into a list then call the .FindAll on it, passing in a delegate. I can create an anonymous delegate to do this, but say i will reuse this many times. How can i dynamically specify an age criteria for the delegate method? Would the only choice be to encapsulate the Predicate method in a class, then create a new instance of that class with my criteria as an instance variable?

Sorting an List<> with my custom order which is stored in another List (C#)?

Can anyone help.. I have a generic list like so
IList<itemTp> itemTps;
itemTp basically is a class (has a number of properties) and one property on this is "code"
I need to be able to sort it an specific order which i have set in another List.
This list is a simple list that lists the order (starting from first to last) like say
code1
code3
code2
code5
(notice it goes from 1 to 3 to 2 to 5 - these are the names, they can be called anything .. the important thing is the order, it doesn't have anything to do with the numbers)
Basically i need ensure the items in itemTp sort according what is present in the other list...
So imagine my Ilist is like this code1,code2,code3,code5 - so once the sort is done
in my
IList<itemTp>
will contain 4 classes that are in order and have the property like code1,code3,code2,code5 (order change)
Any ideas how to do this?
You'll need to create an IComparer that will compare items based on the state of your other list. The advantage of using an IComparer is that you'll be able to build caching logic into your class to avoid repeated IndexOf() lookups if you need that optimization. Also, you'll be able to maintain multiple "other" lists that can be used when appropriate.
class ItemTpComparer : IComparer<itemTp>
{
private IList<codeTp> otherList;
public ItemTpComparer(IList<codeTp> otherList)
{
this.otherList = otherList;
}
public int Compare(itemTp a, itemTp b)
{
return otherList.IndexOf(a.Code) - otherList.IndexOf(b.Code);
}
}
And to perform the sort:
myList.Sort(new ItemTpComparer(otherList));
Sorry if something is wrong, I don't have a C# editor installed here, but it's something like this:
Array.Sort(
itemTps,
delegate(ItemTp a, ItemTp b)
{
return secondList.IndexOf(a.Code) - secondList.IndexOf(b.Code);
});
Note: it may not be the most efficient way, and also there is no checking whether the second list contains the Code at all.
[Edit] As Mehrdad said, Array.Sort doesn't work for generic IList<T>. To sort the array in place, you would need to use the ArrayList.Adapter method to create a wrapper, and then sort it. Since ArrayList.Sort doesn't support a delegate comparison, you need to put the anonymous delegate inside an implementation of IComparer<T>, .
If you need to sort it in a separate list, then it could have sense to use the logic above by creating an array first.
Using C# 3 and LINQ to Objects, I would just create a new list instead of trying to sort the existing one:
void Example()
{
IList<string> codes;
IList<ItemTp> itemTps;
itemTps = codes.Select(code => itemTps.Single(itp => itp.Code == code)).ToList();
}

Categories

Resources