-1

I have a ListCollectionView which holds a collection of scene objects and I need to sort it by scene Number (Scene.SceneNumber) which is a string containing numbers and letters and I need to sort it in a very specific order. First by number then by letter with the lowercase letters first, then the uppercase.

The list needs to look like this:

1
1pt1
1pt2
1A
1Apt1
2
2pt1
2Apt1
3
...

This is what I have so far:

public class SceneComparer : IComparer
{
    private readonly Regex sceneRegEx = new Regex(@"(\d+)(\w+)?", RegexOptions.Compiled);

    public int Compare(object x, object y)
    {
        Scene sceneX = x as Scene;
        Scene sceneY = y as Scene;

        var firstSceneMatches = this.sceneRegEx.Matches(sceneX.SceneNumber);
        var secondSceneMatches = this.sceneRegEx.Matches(sceneY.SceneNumber);

        var matchesCount = Math.Min(firstSceneMatches.Count, secondSceneMatches.Count);
        for (var i = 0; i < matchesCount; i++)
        {
            var firstSceneMatch = firstSceneMatches[i];
            var secondSceneMatch = secondSceneMatches[i];

            var firstSceneNumeric = Convert.ToInt32(firstSceneMatch.Groups[1].Value);
            var secondSceneNumeric = Convert.ToInt32(secondSceneMatch.Groups[1].Value);
            if (firstSceneNumeric != secondSceneNumeric)
            {
                return firstSceneNumeric - secondSceneNumeric;
            }

            var firstSceneAlpha = firstSceneMatch.Groups[2].Value;
            var secondSceneAlpha = secondSceneMatch.Groups[2].Value;
            if (firstSceneAlpha != secondSceneAlpha)
            {
                return string.CompareOrdinal(firstSceneAlpha, secondSceneAlpha);
            }
        }
        return firstSceneMatches.Count - secondSceneMatches.Count;
     }
}

this results in following list

1
1A
1Apt1
1pt1
1pt2
2
2Apt1
2pt1
...

But I need the lowercase letters before the uppercase letters. How do I do this?

Phil
  • 561
  • 2
  • 16
  • 29
  • 1
    What if there would be `sceneComparer.Compare(null, null)` or `sceneComparer.Compare(1, "qwerty")`? Don't use `as` without following null-checking. Also, cosinder implementation of `Comparer` instead of directly implementing non-generic interface. See https://msdn.microsoft.com/en-us/library/cfttsh47(v=vs.110).aspx – Dennis Jul 24 '17 at 06:10
  • 1
    You **really** need to [stop deleting posts](https://stackoverflow.com/questions/45270370/sorting-objects-with-icomparer) and just reposting the same basic question. If you need to make a change, just click the [edit](https://stackoverflow.com/posts/45273455/edit) link and modify the post. Repeatedly deleting your posts will eventually get you banned from asking questions for a time, and when it's revealed that you have been habitually abusing Stack Overflow, your questions will very likely earn down-votes you'd rather not have. – Peter Duniho Jul 24 '17 at 06:30

1 Answers1

-1
//Usage: 
var sortedStrs = strings.OrderBy(s => s, new CollectionComparer<char>(CompareChar)).ToList();

private static int CompareChar(char c1, char c2)
{
    if (char.IsNumber(c1) || char.IsNumber(c2))
    {
        return c1 - c2;
    }

    var s1 = c1.ToString();
    var s2 = c2.ToString();
    var isLowerCaseS1 = s1 == s1.ToLower();
    var isLowerCaseS2 = s2 == s2.ToLower();

    if (isLowerCaseS1 && isLowerCaseS2 || !isLowerCaseS1 && !isLowerCaseS2)
    {
        return c1.CompareTo(c2);
    }

    return isLowerCaseS1 ? -1 : 1;
}


public class CollectionComparer<T> : IComparer<IEnumerable<T>>
{
    private readonly Func<T, T, int> _comparisonFunc;

    public CollectionComparer(Func<T, T, int> comparisonFunc)
    {
        _comparisonFunc = comparisonFunc;
    }

    public int Compare(IEnumerable<T> c1, IEnumerable<T> c2)
    {
        //Ensure.Argument.NotNull(c1);
        //Ensure.Argument.NotNull(c2);

        var collection2 = c2?.ToList() ?? new List<T>();
        var collection1 = c1?.ToList() ?? new List<T>();

        var result = collection1.Select(
            (c, ind) => collection2.Count() > ind ? _comparisonFunc(c, collection2.ElementAt(ind)) : 1)
            .FirstOrDefault(e => e != 0);

        return result != 0 ? result : (collection2.Count > collection1.Count() ? -1 : 0);
    }
}
adPartage
  • 829
  • 7
  • 12
  • Downvotes don't need comments... If you feel need to discuss the post - ask question on meta (https://meta.stackoverflow.com/)... Also in this particular case "I posted wall of code as an answer without any explanations and some $##$@ downvoted my post" may not go very well... May be good idea to search meta for recommendation on whether code-only answers are welcome. – Alexei Levenkov Jul 26 '17 at 02:49