简体   繁体   中英

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"
    }
}

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 AZ, 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

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM