Snickbrack
Snickbrack

Reputation: 956

C# max() not returning the natural highest Value

I have a Dictionary of <string, Point> and the keys in this dictionary look like this:

Now I am using the following statement to receive the heighest Value of the keys:

pointsWhichBelongTogether.Keys.Where(key => key.Contains(searchStringPattern[0] + "_" + searchStringPattern[1] + "_")).OrderBy(x => x, new NaturalStringComparer()).Max()

Which uses the following Compare-Class:

public class NaturalStringComparer : IComparer<string>
    {
        private static readonly Regex _re = new Regex(@"(?<=\D)(?=\d)|(?<=\d)(?=\D)", RegexOptions.Compiled);

        public int Compare(string x, string y)
        {
            x = x.ToLower();
            y = y.ToLower();
            if (string.Compare(x, 0, y, 0, Math.Min(x.Length, y.Length)) == 0)
            {
                if (x.Length == y.Length) return 0;
                return x.Length < y.Length ? -1 : 1;
            }
            var a = _re.Split(x);
            var b = _re.Split(y);
            int i = 0;
            while (true)
            {
                int r = PartCompare(a[i], b[i]);
                if (r != 0) return r;
                ++i;
            }
        }

        private static int PartCompare(string x, string y)
        {
            int a, b;
            if (int.TryParse(x, out a) && int.TryParse(y, out b))
                return a.CompareTo(b);
            return x.CompareTo(y);
        }
    }

So I assume that the List is natural sorted and the Max-Functions just gets the highest value. But the max() returns char_1_9 as the highest value. Does this max()-function a re-sort?

Upvotes: 2

Views: 300

Answers (2)

The string type already implements IComparable<string> so Max() uses this implementation regardless of any previous sorting. I would order your values descending and take the first value:

var max = pointsWhichBelongTogether.Keys
    .Where(key => key.Contains(searchStringPattern[0] + "_" + searchStringPattern[1] + "_"))
    .OrderByDescending(x => x, new NaturalStringComparer())
    .FirstOrDefault();

Upvotes: 1

Ren&#233; Vogt
Ren&#233; Vogt

Reputation: 43876

You have two options:

  • Take the Last from the sorted list or
  • Order descending and take the first

Right now you sort using your comparer, but Max does not use the comparer but the default comparer to find the maximum.

pointsWhichBelongTogether.Keys.Where(key => key.Contains(searchStringPattern[0] + "_" + searchStringPattern[1] + "_"))
    .OrderBy(x => x, new NaturalStringComparer()).Last();

or

pointsWhichBelongTogether.Keys.Where(key => key.Contains(searchStringPattern[0] + "_" + searchStringPattern[1] + "_"))
    .OrderByDescending(x => x, new NaturalStringComparer()).First();

Edit: in a previous version I suggested to pass the comparer to Max, but it seems there is no overload that takes a comparer, only a selector.

Upvotes: 5

Related Questions