Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

At least one object must implement IComparable calling OrderBy()

Tags:

c#

linq

json.net

I already saw this question, but i didn't find my happiness with the answers...

I'm trying to do that:

var coll = JsonConvert.DeserializeObject<ObservableCollection<ArticleJSON>>(json);
coll = coll.OrderBy(a => a.tags).Distinct().ToList();

Throws an error:

At least one object must implement IComparable.

For the moment i didn't find the solution so i did that:

List<string> categories = new List<string>();    
var coll = JsonConvert.DeserializeObject<ObservableCollection<ArticleJSON>>(json);

for (int i = 0; i < test.Count; ++i)
{
    for (int j = 0; j < test[i].tags.Count; ++j)
    {
        _categories.Add(test[i].tags[j]);
    }
}

categories = _categories.Distinct().ToList();

It works but i'm curious to know why the first one don't work.

EDIT :

My data come from a JSON :

            'tags': [ 

                                        'Pantoufle',
                                        'Patate'
                                     ]
                            },
            public List<string> tags { get; set; }
like image 584
Fly_federer Avatar asked Apr 06 '15 03:04

Fly_federer


People also ask

Does OrderBy use IComparable?

OrderBy uses the default comparer Comparer<T>. Default which in turn will default to use the IComparable<T> implementation for T , or the non-generic IComparable if the former does not exist.

How do you implement IComparable interface?

Implementing IComparable Interface requires:Adding a method CompareTo() which receives an object and returns an integer. The CompareTo() method depending on the comparison: returns 0, if the current instance's property is equal to the temporary variable's property.

What is use of IComparable in C#?

CompareTo(Object) Method (System) Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object.


2 Answers

To order a set of things, there must be a way to compare two things to determine which one is larger, or smaller or whether they are equal. Any c# type that implements the IComparable interface, provides the means to compare it versus another instance.

Your tags field is a list of strings. There is no standard way to compare two lists of strings in that manner. The type List<string> does not implement the IComparable interface, and thus cannot be used in a LINQ OrderBy expression.

If for example you wanted to order the articles by the number of tags, you could do that like this:

coll = coll.OrderBy(a => a.tags.Count).ToList();

because Count will return an integer and an integer is comparable.

If you wanted to get all unique tags in sorted order, you could do that like this:

var sortedUniqueTags = coll
    .SelectMany(a => a.Tags)
    .OrderBy(t => t)
    .Distinct()
    .ToList();

because a string is comparable.

If you really know how to compare two lists of strings, you could write your own custom comparer:

public class MyStringListComparer : IComparer<List<string>>
{
    // implementation
}

and use it like this:

var comparer = new MyStringListComparer();
coll = coll.OrderBy(a => a.tags, comparer).Distinct().ToList();
like image 97
Alex Avatar answered Sep 18 '22 17:09

Alex


ArticleJSON does not implement IComparable while String does. The compiler does not know how to compare ArticleJSON for the OrderBy() you are calling. It works fine when you are using a list of string because of this.

like image 26
RobbieK Avatar answered Sep 22 '22 17:09

RobbieK