Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linq OrderBy not sorting correctly 100% of the time

Tags:

c#

linq

I'm using the Linq OrderBy() function to sort a generic list of Sitecore items by display name, then build a string of pipe-delimited guids, which is then inserted into a Sitecore field. The display name is a model number of a product, generally around 10 digits. At first it seemed like this worked 100% of the time, but the client found a problem with it...

enter image description here

This is one example that we have found so far. The code somehow thinks IC-30R-LH comes after IC-30RID-LH, but the opposite should be true.

I put this into an online alphabetizer like this one and it was able to get it right...

enter image description here

I did try adding StringComparer.InvariantCultureIgnoreCase as a second parameter to the OrderBy() but it did not help.

Here's the code... Let me know if you have any ideas. Note that I am not running this OrderBy() call inside of a loop, at any scope.

    private string GetAlphabetizedGuidString(Item i, Field f)
    {
        List<Item> items = new List<Item>();
        StringBuilder scGuidBuilder = new StringBuilder();

        if (i != null && f != null)
        {
            foreach (ID guid in ((MultilistField)f).TargetIDs)
            {
                Item target = Sitecore.Data.Database.GetDatabase("master").Items.GetItem(guid);
                if (target != null && !string.IsNullOrEmpty(target.DisplayName)) items.Add(target);
            }

            // Sort it by item name.
            items = items.OrderBy(o => o.DisplayName, StringComparer.InvariantCultureIgnoreCase).ToList();

            // Build a string of pipe-delimited guids.
            foreach (Item item in items)
            {
                scGuidBuilder.Append(item.ID);
                scGuidBuilder.Append("|");
            }

            // Return string which is a list of guids.
            return scGuidBuilder.ToString().TrimEnd('|');
        }

        return string.Empty;
    }
like image 358
Paul Avatar asked Dec 29 '15 16:12

Paul


1 Answers

I was able to reproduce your problem with the following code:

var strings = new string[] { "IC-30RID-LH", "IC-30RID-RH", "IC-30R-LH", "IC-30R-RH"};
var sorted = strings.OrderBy(s => s);

I was also able to get the desired sort order by adding a comparer to the sort.

var sorted = strings.OrderBy(s => s, StringComparer.OrdinalIgnoreCase);

That forces a character-by-character (technically byte-by-byte) comparison of the two strings, which puts the '-' (45) before the 'I' (73).

like image 86
Craig W. Avatar answered Oct 02 '22 00:10

Craig W.