kame
kame

Reputation: 21960

Find the minimum of a number sequence with negative numbers with Linq

The following code doesn't give the expected minimum -1. Instead I get 0. Do you know why?

class MainClass
{
    public static void Main (string[] args)
    {
        string numbers = "-1 0 1 2 3 4 5";
        Console.WriteLine (numbers.Split (' ')[0]);     // output: -1
        string max = numbers.Split(' ').Max();
        string min = numbers.Split(' ').Min();
        Console.WriteLine("{0} {1}", max, min);         // output: "5 0"
    }
}

Upvotes: 1

Views: 1684

Answers (3)

Matthew Watson
Matthew Watson

Reputation: 109567

There are two reasons for this behaviour:

  1. You are sorting strings instead of numbers. This means that behind the scenes, Linq is using String.CompareTo() to compare the strings.
  2. String.CompareTo() has special behaviour for -, which it treats as a HYPHEN and not a MINUS. (Note: This hyphen should not be confused with a soft hyphen which has the character code U00AD.)

Consider this code:

Console.WriteLine("-1".CompareTo("0")); // 1
Console.WriteLine("-1".CompareTo("1")); // 1
Console.WriteLine("-1".CompareTo("2")); // -1

Notice how, counter-intuitively, the "-1" is AFTER "0" and "1" but BEFORE "2".

This explains why when ordering the strings, the "-1" is neither the max nor the min.

Also see the answer to this question for more details.

Upvotes: 2

Sayse
Sayse

Reputation: 43300

I've not fully defined an answer yet but it appears to be because the - isn't accounted for.. you can confirm this with CompareOrdinal

    Console.WriteLine(String.CompareOrdinal("-1", "0"));  // -3 meaning -1 min
    Console.WriteLine(String.Compare("-1", "0"));  // 1 meaning 0 min

Either way, you are trying to compare numbers so you should treat them as numbers so similar subtleties dont appear.


Attempted explanation...

String implements IComparable<string> so String.Min uses that implementation (see remarks). Which in turn uses CompareTo,

Now in the notes for this method

Character sets include ignorable characters. The CompareTo(String) method does not consider such characters when it performs a culture-sensitive comparison. For example, if the following code is run on the .NET Framework 4 or later, a comparison of "animal" with "ani-mal" (using a soft hyphen, or U+00AD) indicates that the two strings are equivalent.

(Emphasis mine)

As you see. the - is ignored hence 0 which has a smaller value in an ascii table is used for the comparison

Upvotes: 2

MajkeloDev
MajkeloDev

Reputation: 1661

It's a string so Getting max from string is totally different than getting max from a number. For instance if You would have an array like below

char[] someCharArray = new char[] { '1', '12', '2' }

calling Max() on this array would result with 2 as 2 is "higher" in string order than 12.

Thinking about Max/Min value from string/char You need to think about alphabetical order. If You have a colection of letters A-Z, calling Min() will return A, calling Max() will return Z.

To get Max/Min in numerical order You need to cast to some Number type like int. See below:

string numbers = "-1 0 1 2 3 4 5";
int min = numbers.Split(' ').Select(x => int.Parse(x)).Min();
Console.WriteLine(min); // gives You -1

Upvotes: 2

Related Questions