Solved

sorting a list with linq myList.Sort(r => r.CompareTo(myobj));

Posted on 2011-09-30
14
292 Views
Last Modified: 2012-06-21
Hi there;

I have a question regarding in linq in C# for sorting a list.

I have a function foo;

void foo(AAA myobj)
{
...

myList.Sort(r => r.CompareTo(myobj));
}

Please let me say I implement the CompareTo method of IComparable<MyClass>.

public int CompareTo(MyClass m) is the signiture of the implemented comparator.

but it gives an error, so could you tell me what is the problem?

Kind regards.
0
Comment
Question by:jazzIIIlove
  • 7
  • 6
14 Comments
 
LVL 4

Expert Comment

by:theHollow
ID: 36893159
Hello
How did you implement the "CompareTo" method?
Did you add the method alone, or did you also inherit the "IComparable<MyClass>" interface as well?
Because you will have to do that.

If your list is a "IEnumerable<MyClass>", you can also sort a list by doing this:

items = from i in items 
            orderby i.SomeProperty descending, i.SomOtherProperty ascending
            select i;

Open in new window


Hope it helped :-)
0
 
LVL 6

Expert Comment

by:effes
ID: 36893181
Try
myList.Sort((x,y) => x.CompareTo(y));

Open in new window

The Sort method expects you to pass it a Comparison delegate, i.e. something that represents a method that takes two objects of a given type as parameters and compares them. (See http://msdn.microsoft.com/en-us/library/w56d4y5z.aspx and http://msdn.microsoft.com/en-us/library/tfakywbh.aspx for reference.)
0
 
LVL 12

Author Comment

by:jazzIIIlove
ID: 36893469
Hi,

@thehollow:
Please let me say I implement the CompareTo method of IComparable<MyClass>.

public int CompareTo(MyClass m) is the signiture of the implemented comparator. So it takes 1 parameter, not 2. I cannot change my CompareTo function.
@effes:
Your code is not working as It takes to params. myList.Sort((x,y) => x.CompareTo(y));
0
 
LVL 12

Author Comment

by:jazzIIIlove
ID: 36893517
Not to but two :)
0
 
LVL 6

Expert Comment

by:effes
ID: 36893697
What doesn't work / what error(s) do you get?

My code has two parameters because the Sort method needs them. Internally it takes two elements from your list and runs it through the compare method it is provided. The call to your CompareTo method is just the same as it is in the code you provided: Take an object of the MyClass class and call its CompareTo method, passing it another object of type MyClass as parameter (the only one).
I don't see why this shouldn't work.

Maybe I misunderstood your question?
0
 
LVL 12

Author Comment

by:jazzIIIlove
ID: 36893916
Ok, let me give more detail:
[Serializable]
Class A : IComparable
{

int CompareTo(Class A otherObj)
{
}

}

Class B
{

void AFunc(Class A myObj)
{

//MyList here
//your code here?

}

Is it like that?

Thanks for your patience.

Kind regards.
}
0
 
LVL 6

Expert Comment

by:effes
ID: 36893982
As long as myList is a List<ClassA> it should work.
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 6

Expert Comment

by:effes
ID: 36894581
It just occurred to me that since your class implements IComparable<MyClass> it enough to use the Sort method without parameters. It will use your CompareTo method automatically. So in this case
myList.Sort((x,y) => x.CompareTo(y));

Open in new window

and
myList.Sort();

Open in new window

should give you the same result.

Sorry, I was kinda fixated on the first one.
0
 
LVL 12

Author Comment

by:jazzIIIlove
ID: 36894983
So, Sort without params is OK even i implemenyed CompareTo function of IComparable Interface? I want to use CompareTo function as i implemented already.

Kind regards.
0
 
LVL 6

Expert Comment

by:effes
ID: 36895561
Using Sort without parameters is OK because you implemented IComparable,
Sort will check whether the type it has to sort implements that interface. If it does, Sort will use the corresponding CompareTo method. So your CompareTo will be called autmatically.
You can check that by setting a breakpoint inside CompareTo.
0
 
LVL 12

Author Comment

by:jazzIIIlove
ID: 36897319
ok, just to populate;

When I write this:
Class A
{
public int DoThis(Class B b)
{
myList.Sort((r, b) => r.CompareTo(b));
}

}

I have the following error:
Error      2      A local variable named 'b' cannot be declared in this scope because it would give a different meaning to 'b', which is already used in a 'parent or current' scope to denote something else      

I got it Sort without params it works but I want to use the incoming parameter but failed...

Regards.
0
 
LVL 6

Expert Comment

by:effes
ID: 36902515
The lambda expression that you pass to the Sort method ("(r, b) => r.CompareTo(b)") is just an anonymous function. In your case it says: this is a function that takes two parameters, one named "r" and one named "b". The problem with this is that the name "b" is already in use by the parameter of the DoThis method.
You would have to rename "b" to "c" or something ("(r, c) => r.CompareTo(b)"). You can still call CompareTo with "b", but calling Sort like that will almost certainly fail, because the results returned by CompareTo are inconsistent.

What are you trying to achieve when you use the incoming parameter?
0
 
LVL 12

Author Comment

by:jazzIIIlove
ID: 36906712
Aha...So lambda expressions cannot use input parameters of a function?

And i always get confused that anonymous function. I mean i don't declare 'r' but using it. How? What is the logic there?

Kind regards.
0
 
LVL 6

Accepted Solution

by:
effes earned 500 total points
ID: 36912118
What's happening is this: The lambda expression is an anonymous function. On the left side of the lambda operator (the "=>") you specifiy the input parameters for the function. That's like declaring new variables whose scope is just the body of the lambda expression (the part to the right of the lambda operator). The only one who can pass values to those parameters is the "caller" of the expression (in your case the Sort method).
Inside the body of the expression you have access to the parameters you defined and to all variables in whose scope the expression is declared.
So in your case you have access to the input parameter "b" of the outer method "DoThis" and the input parameter "b" of the lambda expression. The compiler has no way of knowing which one of the b's you actually mean.

Now, if you rename the second parameter of the lambda eypression from "b" to "c" ("(r, c) => r.CompareTo(b)") to avoid the ambiguity, the code will compile. The problem begins when the Sort method kicks in: it will take two elements in the list and pass it to the lambda expression, because it wants to know how they compare. Inside the lambda expression they are accessible via the input parameters "r" and "c". But the lambda expression only takes the first element ("r") and compares it to an element from outside the scope of the lambda expression ("b"). "c" is completely ignored. The Sort method calls the lamba expression again and again with new combinations of elements in the list, until the are in the right order. Since the lambda expression never compares the two elements that are passed to it, but only the first one to a fixed element ("b" never changes as long as Sort runs), Sort will at some point consider the results inconsistent and throw an exception (this is done to prevent it from running endlessly).

That's why I asked what you are trying to achieve. It would make it easier to tweak things to work better for you.
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Suggested Solutions

Entity Framework is a powerful tool to help you interact with the DataBase but still doesn't help much when we have a Stored Procedure that returns more than one resultset. The solution takes some of out-of-the-box thinking; read on!
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
This video discusses moving either the default database or any database to a new volume.
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now