Martin at Mennt
Martin at Mennt

Reputation: 5737

Sort a list by reference C#

I have a List<Unit> where Unit contains Name and Value. In this object I store information about apparel sizes Name contains size names (S,M,L,XL..) and Value contains the quantity of that size.

This unit list is contained from a database, but the list comes in random order, so in the liste it might be like this:

Unit(M,3)
Unit(S,1)
Unit(XXL,2)
Unit(L,2)

I would like to sort the list so that it become more like this:

Unit(S,1)
Unit(M,3)
Unit(L,2)
Unit(XXLL,2)

I cant order on the string ASCE or DESC since it M comes before S and so on. Then I thought I might create an reference Array with the correct order (XXS,XS,S,M,L,XL,XXL,XXXL), but how can I sort my list according to the reference.

Or are there other clever ways of doing this?

Update

Thanks for all good answers, I landed on the Enum solution, and it finally looks like this:

public class Unit
{
    public Unit()
    {
    }

    public Unit(string name, int value)
    {
        Value = value;
        SizeCode = AssignSizeCode(name);
    }

    public SizeCode SizeCode { get; set; }
    public int Value { get; set; }

    private SizeCode AssignSizeCode(string name)
    {
        switch (name)
        {
            case "XXS":
                return SizeCode.XXS;
            case "XS":
                return SizeCode.XS;
            case "S":
                return SizeCode.S;
            case "M":
                return SizeCode.M;
            case "L":
                return SizeCode.L;
            case "XL":
                return SizeCode.XL;
            case "XXL":
                return SizeCode.XXL;
            case "XXXL":
                return SizeCode.XXXL;
            default:
                return SizeCode.Unknown;
        }
    }

}

public enum SizeCode
{
    XXS = 1,
    XS = 2,
    S = 3,
    M = 4,
    L = 5,
    XL = 6,
    XXL = 7,
    XXXL = 8,
    Unknown = 9
}

And I sort it like this:

units = units.OrderBy(x => (int)x.SizeCode).ToList();

Any comments, or things I can improve?

Upvotes: 2

Views: 2338

Answers (5)

Amittai Shapira
Amittai Shapira

Reputation: 3827

You can do exactly what MSDN suggest here:

// First, declare a few classes that implement the IComparer interface.
public class CompareShirtSize : IComparer<string>
{
    // Because the class implements IComparer, it must define a 
    // Compare method. The method returns a signed integer that indicates 
    // whether s1 > s2 (return is greater than 0), s1 < s2 (return is negative),
    // or s1 equals s2 (return value is 0). This Compare method compares strings. 
    public int Compare(string size1, string size2)
    {
        // Do size comarison here
        return ConvertSizeToInt(size1) - ConvertSizeToInt(size2);
    }

    private int ConvertSizeToInt(string size)
    {
      switch (size)
      {
        case "XXS":
            return 1;
        case "XS":
            return 2;
        case "S":
            return 3;
        case "M":
            return 4;
        case "L":
            return 5;
        default:
           // some error handling
       }
}


// The following method tests the Compare methods defined in the previous classes.
public static void OrderByIComparer()
{
    List<Unit> units;

     // Sort the elements of the array alphabetically.
    var sortedList = units.OrderBy(unit => unit.Size, new CompareShirtSize ());
}

Upvotes: 1

alexsuslin
alexsuslin

Reputation: 4225

Ok, I consider you should have OrderIndex column in your database and sort by that column.

the dirty way is to have your own class with interface : IComparer or do the same as delegate for sorting.

Check ICompararer in MSDN: http://msdn.microsoft.com/en-us/library/system.collections.icomparer.aspx

Upvotes: 2

Jayanga
Jayanga

Reputation: 887

How about using a enum

public enum Size
    {
        Small = 1,
        Medium = 2,
        // etc 

    }

Then you can convert the enum value in Unit class to int and sort by the integer value.

Upvotes: 3

Rohan Prabhu
Rohan Prabhu

Reputation: 7302

You simply need to use a Comparison Delegate. Firstly, make a function that just assigns a number to every size and then use that for comparison:

(I am not sure whether your sizes are stored as a String as an enum; but I would recommend storing them as an enum with the ordinal numbers in order of the sizes, increasing or decreasing. This will help make your comparison delegate faster and simpler).

public class ShirtSizeCompare {
    private static int getIndex(Unit x) {
        if(x == Null) { return -1; }

        if(x.size == "S") {
            return 0;
        } else if(x.size == "M") {
            return 1;
        }

        ///...
    }            

    private static int CompareShirts(Unit x, Unit y) {
        int _x = getIndex(x);
        int _y = getIndex(y);

        if(_x < _y) {
            return -1;
        } else if(_x == _y) {
            return 0;
        } else {
            return 1;
        }
    }
}

Then, simply use the Comparison delegate to sort the list:

List<Unit> unitList;
unitList.sort(CompareShirts);

The comparison delegate basically takes as input two variables x and y and returns:

<0 (if x < y)
>0 (if x > y)
0  (if x == y)

Check this page for more information: http://msdn.microsoft.com/en-us/library/w56d4y5z.aspx

Upvotes: 0

ken2k
ken2k

Reputation: 48995

You could add a Size property of type int in your class Unit. Then sort your list using this Size property.

public class Unit1
{
    public Unit1(string name)
    {
        this.Name = name;

        switch (this.Name)
        {
            case "XXS":
                this.Size = 1;
                break;
            case "XS":
                this.Size = 2;
                break;
            case "S":
                this.Size = 3;
                break;
            case "M":
                this.Size = 4;
                break;
            case "L":
                this.Size = 5;
                break;
        }
    }

    public string Name { get; set; }

    public int Size { get; private set; }

    public int Value { get; set; }
}

private static void Main(string[] args)
{
    List<Unit1> list1 = new List<Unit1>();
    list1.Add(new Unit1("XS") { Value = 1 });
    list1.Add(new Unit1("M") { Value = 1 });
    list1.Add(new Unit1("S") { Value = 1 });
    list1.Add(new Unit1("L") { Value = 1 });

    var sortedList = list1.OrderBy(z => z.Size).ToList();
}

Upvotes: 0

Related Questions