开发者

Ordering items in IList<T>

开发者 https://www.devze.com 2023-04-03 11:45 出处:网络
I have a list IList<IRule> allRules = new List<IRule>() in that list i go ahead and add different type of rules at random i.e.

I have a list

IList<IRule> allRules = new List<IRule>()

in that list i go ahead and add different type of rules at random i.e.

allRules.add(DeleteRule1)
allRules.add(AddRule1)
allRules.add(DeleteRule2) 
allRules.add(EditRule1)
allRules.add(AddRule2)
allRules.add(DeleteRule3)

all this works fine the thing i am trying to figure out is that i need this list to be sorted开发者_运维技巧 so it has all the AddRules first then EditRules and finally DeleteRules.

Can any one specify an approach I can take ?

Let me know if this does not make sense and I will try to explain in more detail.

Many Thanks


There doesn't seem to be a built-in way to sort an IList<T>.

Option 1: Declare the variable to be of type List<T> and use the List<T>.Sort Method.

List<IRule> allRules = new List<IRule>();
allRules.add(DeleteRule);
...
allRules.Sort();

Option 2: Replace the list with a new list that is ordered.

IList<IRule> allRules = new List<IRule>();
allRules.add(DeleteRule);
...
allRules = allRules.OrderBy(x => x).ToList();

Option 3: Implement quick-sort for IList<T>.

Option 4: Choose a different collection type that automatically keeps its elements in a certain order.


There is a SortedList class which might be what your are looking for

  • In collections - http://msdn.microsoft.com/en-us/library/system.collections.sortedlist.aspx
  • Generic version - http://msdn.microsoft.com/en-us/library/ms132319.aspx


I assume that you have three classes that implement IRule (AddRule, EditRule, DeleteRule).

If you can change the type of allRules from IList to List, you can use the List<T>.Sort(Comparison<T>) method. Comparison is a generic delegate with the signature

public delegate int Comparison<in T>(T x,T y)

so you'll need something like this:

public int IRuleComparer(IRule first, IRule second)
{
  //build a table of type weights (this could be made static)
  Dictionary<Type, int> typeWeights = new Dictionary<Type, int>();
  typeWeights.Add(typeof(AddRule), 1);
  typeWeights.Add(typeof(EditRule), 2);
  typeWeights.Add(typeof(DeleteRule), 3);

  //get the types of the arguments
  Type firstType = first.GetType();
  Type secondType = second.GetType();

  //are the types valid?
  if (!typeWeights.ContainsKey(firstType))
     throw new Exception("invalid first type");

  if (!typeWeights.ContainsKey(secondType))
     throw new Exception("invalid second type");

  //compare the weights of the types
  return typeWeights[firstType].CompareTo(typeWeights[secondType]);
}

Also, take note that the Sort implementation uses the quick sort algorithm, that is not a stable sort, i.e it might mess the relative order of AddRules, so in your example, AddRule2 could get sorted before AddRule1.


Alternatively, you could use LINQ with something like this:

public int GetRuleWeight(IRule item)
{
   //build a table of type weights (this could be made static)
   Dictionary<Type, int> typeWeights = new Dictionary<Type, int>();
   typeWeights.Add(typeof(AddRule), 1);
   typeWeights.Add(typeof(EditRule), 2);
   typeWeights.Add(typeof(DeleteRule), 3);

  Type itemType = item.GetType();

  if (!typeWeights.ContainsKey(itemType))
     throw new Exception("invalid type");

  return typeWeights[itemType];
}

allRules = allRules.OrderBy(item => GetRuleWeight(item)).ToList();

this will work with IList (even with IEnumerable), so you wont have to change the type of allRules.


You should implement Your own IComparer and than use it in Sort method.


a simplistic approach is to create 3 separate lists for each type then copy items back to the list from AddRulesList then EditRulesList ..etc, this is fast and only requires too loops.

if you want to be generic and rely on built in sorting capabilities you will need to implement comparison operation for the IRule type

http://codebetter.com/davidhayden/2005/03/06/implementing-icomparer-for-sorting-custom-objects/


List has a sort method where you can pass a comparator that can do the comparison algorithm for you.

using System;
using System.Collections.Generic;

public class Example
{
    private static int MyRuleComparer(Rule x, Rule y)
    {
      // return -1, 0 or 1 by comparing x & y
    }

    public static void Main()
    {
        List<Rule> allRules= new List<Rule>();
        allRules.Add(...);
        allRules.Add(...);
        allRules.Add(...);
        allRules.Add(...);

        allRules.Sort(MyRuleComparer);

    }
}

Also as Sharique says, you could use a SortedList class. This uses an IComparer instance to do the work:

using System; using System.Collections.Generic;

public class Example
{
    public class MyComparer : IComparer  {
       int IComparer.Compare( Object x, Object y )  
       {
          // return -1, 0 or 1 by comparing x & y
       } 
    }  

    public static void Main()
    {
        SortedList allRules = new SortedList(new MyComparer ())
        allRules.Add(...); // Sorted each time
        allRules.Add(...); // Sorted each time
        allRules.Add(...); // Sorted each time
        allRules.Add(...); // Sorted each time
    }
}


List<T> Class:

The List is not guaranteed to be sorted. You must sort the List before performing operations (such as BinarySearch) that require the List to be sorted.

You might want to look at the SortedList (but it is not type safe), or add some kind or Order filed to IRule, then sort using IEnumerable<T>.OrderBy(...).

Edit

There is a generic version of SortedList.


I would go for simplicity, since I'm guessing that we're not talking about a huge list here.

Assmptions: C# 3, and that appropriate classes or interfaces AddRule, EditRule, DeleteRule exist

var sortedRules = 
           allRules.OfType<AddRule>()
   .Concat(allRules.OfType<EditRule>())
   .Concat(allRules.OfType<DeleteRule>());
0

精彩评论

暂无评论...
验证码 换一张
取 消