D J
D J

Reputation: 7028

OrderBy list having different type of values

I have list of multiple types. Somthing like

List<object> list = new List<object>() { 11.21, 323, 4, 3221, 221, 2, "asd" };
var qu = list.OrderBy((o) => o);
qu.ToList().ForEach((e) => Console.WriteLine(e)); // throws exception

Exception thrown is "Object must be of type Int32."

How can I write the Linq to sort such a list.

Upvotes: 3

Views: 1597

Answers (4)

Jack
Jack

Reputation: 1084

I would use a custom comparer:

o = o.OrderBy(x => x, new MyComparer());

...

internal class CustomComparer : IComparer<object>
{
    public int Compare(object x, object y)
    {
        if (x is string && y is string)
        {
            return ((string)x).CompareTo((string)y);
        }
        else if (x is string && IsNumber(y))
        {
            return -1;
        }
        else if (y is string && IsNumber(x))
        {
            return 1;
        }
        else if (IsNumber(x) && IsNumber(y))
        {
            return (Convert.ToDouble(x)).CompareTo(Convert.ToDouble(y));
        }
        else
        {
            throw new NotSupportedException();
        }
    }

    private bool IsNumber(object o)
    {
        var t = o.GetType();
        if (o is int || o is double || o is float || o is long)
            return true;
        return false;
    }
}

Upvotes: 1

Selman Gen&#231;
Selman Gen&#231;

Reputation: 101681

How about implementing IComparer<T> like this ?

public class MyComparer : IComparer<object>
{
    public int Compare(object x, object y)
    {
        var type = x.GetType();
        var type2 = y.GetType();
        if (type == typeof(string) && type2 == typeof(string))
        {
            return String.Compare((string)x, (string)y);
        }
        else if (type.IsValueType && type2.IsValueType)
        {
            var comp = Comparer<double>.Default;
            return comp.Compare(Convert.ToDouble(x), Convert.ToDouble(y));
        }
        else
        {
            return 0;
        }
    }
}

And use it:

List<object> list = new List<object>() { 11.21, 323, 4, 3221, 221, 2, "asd" };
var qu = list.OrderBy(o => o, new MyComparer());
qu.ToList().ForEach((e) => Console.WriteLine(e));

Upvotes: 0

MarcinJuraszek
MarcinJuraszek

Reputation: 125610

That's one of the most crazy LINQ queries I've ever written...

var qu = list.Select(x =>
                        {
                            decimal? d;
                            try
                            {
                                d = Convert.ToDecimal(x);
                            }
                            catch (FormatException)
                            {
                                d = null;
                            }

                            return new { v = x, d, s = x.ToString() };
                        }).GroupBy(x => x.d.HasValue)
                          .Select(g =>
                              g.Key
                              ? g.OrderBy(x => x.d.Value).Select(x => x.v)
                              : g.OrderBy(x => x.s).Select(x => x.v))
                          .SelectMany(x => x)
                          .ToList();

Returns all numeric values first, (sorted using its value) and then all strings sorted using standard string comparison.

Upvotes: 3

Ofer Zelig
Ofer Zelig

Reputation: 17470

List<object> list = new List<object>() { 11.21, 323, 4, 3221, 221, 2, "asd" };
var qu = list.OrderBy((o) => o.ToString());
qu.ToList().ForEach((e) => Console.WriteLine(e));

You must cast your items to something, not necessarily to int. In this example I casted everything to string. Just bear in mind that the OrderBy operation will sort by string and not numerically of course. You can't sort numerically because you have a string item in your list.

Upvotes: 2

Related Questions