Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using float + Lambda Expressions C#

Tags:

c#

lambda

var distances = new Dictionary<char, float>();
var nodes = new List<char>();

I have this line to find the smallest distance

nodes.Sort((x, y) => distances[x] - distances[y]);

When I use int it works well, but when I used float I got a message

cannot convert lambda expression to type 'System.Collections.Generic.IComparer' because it is not a delegate type

Do you have an idea?

like image 715
Mat Avatar asked Dec 02 '22 15:12

Mat


2 Answers

First off, your original program is a bad programming practice when the values are integers. It works for chars, but I would avoid this bad programming practice.

The delegate you pass to the sort function must have a number of properties; in particular it must return a negative int if x is smaller than y, a positive int if x is greater than y, and zero if they are equal. Your original lambda does not do that for integer values. (See if you can find two integers x and y such that x is smaller than y but x - y is positive.)

The delegate must also impose a total order. In a total order:

  • Transitivity must hold. If A == B and B == C then A must equal C. If A < B and B < C then A must be smaller than C. And so on.
  • It must be antisymmetric. That is, if A < B then B > A, and so on.

Subtraction does not meet these conditions in integers. The correct code is to actually write a comparison.

nodes.Sort((x, y) => x < y ? -1 : (x > y ? 1 : 0));

That then works well for chars and floats, provided there are no NaNs. If you have NaNs then you need to do extra work to impose a total order.

I would also point out that this ordinal comparison on chars is usually not the comparison you want. Sure, this will correctly note that e is smaller than z, but simple ordinal comparison also says that z is smaller than é, which is likely not what you want. Character ordering depends on culture; are you sure you want to order by the order that the Unicode committee just happened to impose?

For more on this topic see my series of articles; it begins here:

http://ericlippert.com/2011/01/20/bad-comparisons-part-one/

like image 200
Eric Lippert Avatar answered Dec 10 '22 14:12

Eric Lippert


You can't convert your lambda expression into a Comparison<char> (which is what you want) because it returns a float - you've effectively got a Func<char, char, float> there, whereas Comparison<char> is closer to Func<char, char, int>.

The simplest approach is to use float.CompareTo:

nodes.Sort((x, y) => distances[x].CompareTo(distances[y]));

Or if you don't need to sort in-place, you could use LINQ:

var sorted = nodes.OrderBy(x => distances[x]);
like image 45
Jon Skeet Avatar answered Dec 10 '22 14:12

Jon Skeet