Reputation: 7028
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
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
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
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
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