locked
Sorting order of the elemtns RRS feed

  • Question

  • Hi All,

    I will be highly obliged if you could solve my issue. 

    The issue which I am facing that is about the sorting order of the Special Chars, Numbers and Alphbets.

    I think default sorting is Special Chars -> Numbers -> Alphbets in Ascending order. Suppose I have below data 

    "Test1","12234","23","@abc","@123"

    if we sort the above data in c# in ascending order then we will get the following result

    "@123","@abc","12234","23","test1"

    But as per my requirement , I want the sorting to be Numbers -> Special Chars ->Alphabets

    The above result should come as 

    "12234","23","@123","@abc","test1"


    And these results I am displaying in the DataGrid, So I want to change the way of default sorting of the grid so that the above result can be achieved.


    Thanks in advance.


    Dharmendra Kumar SE, CSC India. Noida,+91-9911308352

    Tuesday, April 8, 2014 7:24 PM

Answers

  • But as per my requirement , I want the sorting to be Numbers -> Special Chars ->Alphabets

    The above result should come as 

    "12234","23","@123","@abc","test1"


    Just be aware that when sorting strings the order will not reflect the *values* such as
    numeric order of any numbers represented. For example, given "15" and "123" then "123"
    will come before "15" in ascending order. Because the comparison will stop as soon as
    the 5 and 2 are compared. If you wanted the numeric order of the values represented in
    the strings (e.g. - 15 is less than 123) then you would have to do additional work.

    - Wayne


    • Edited by WayneAKing Tuesday, April 8, 2014 11:12 PM
    • Marked as answer by Caillen Thursday, April 17, 2014 9:56 AM
    Tuesday, April 8, 2014 11:06 PM
  • I wrote this.  It uses a LexicographicalComparison to compare strings according to their elements.  And it uses a ClassifiedComparison to compare characters first based on their classification.

    Then I provided a classification function that identifies numbers, alphabetical characters and special chars, as an enumertion, which in turn controls the collating order.

    Here's my example:

    class Program
    {
        /// <summary>
        /// Compares two sequences lexicographically based on the ordering of their elements.
        /// In the case that the elements are equal, the next elements in the sequence are compared.
        /// Non-existent elements precede existing elements.  e.g.:  "ab" &lt; "abc"
        /// For example: compares strings by comparing their chars.
        /// </summary>
        /// <typeparam name="T">The type of the elements of the sequences.</typeparam>
        /// <param name="componentComparison">A user-provided comparison function that
        /// compares elements.</param>
        /// <returns>a = b : 0; a &lt; b : -1; a &gt; b : 1</returns>
        static int LexicographicalComparison<T>(
            IEnumerable<T> a, IEnumerable<T> b,
            Comparison<T> componentComparison )
        {
            // Lexicographical comparison
            IEnumerator<T> ca = a.GetEnumerator();
            IEnumerator<T> cb = b.GetEnumerator();
            while( true ) {
                if( !ca.MoveNext() )
                    if( !cb.MoveNext() ) return 0;
                    else return -1;
                if( !cb.MoveNext() ) return 1;
                int result = componentComparison( ca.Current, cb.Current );
                if( result == 0 ) continue;
                return result;
            }
        }
    
        /// <summary>
        /// Compares items first according to their classification, then according to the
        /// items themselves.
        /// </summary>
        /// <typeparam name="T">The type of the items themselves.</typeparam>
        /// <typeparam name="C">The type of the classification of the items.</typeparam>
        /// <returns>a = b : 0; a &lt; b : -1; a &gt; b : 1</returns>
        static int ClassifiedComparison<T, C>(
            T a, T b,
            Func<T, C> classifier )
            where C : IComparable
            where T : IComparable
        {
            int itemCompare = a.CompareTo( b ); // Assume identical items have identical classifications.
            if( itemCompare == 0 ) return 0;
            int classCompare = classifier( a ).CompareTo( classifier( b ) );
            if( classCompare == 0 ) return itemCompare;
            return classCompare;
        }
    
        enum CharClass
        {
            // The order you put these enums in determines the collating order
            Numbers,
            Special,
            Alphabets,
        }
    
        static CharClass GetCharClass( char c )
        {
            if( char.IsDigit( c ) ) return CharClass.Numbers;
            if( char.IsLetter( c ) ) return CharClass.Alphabets;
            return CharClass.Special;
        }
    
        static void Main( string[] args )
        {
            List<string> words = new List<string>() { "Test1", "12234", "23", "@abc", "@123" };
            words.Sort( ( a, b ) => LexicographicalComparison<char>( a, b,
                ( x, y ) => ClassifiedComparison( x, y, GetCharClass ) ) );
            Console.WriteLine( string.Join( ", ", words ) );
        }
    }
    

    • Marked as answer by Caillen Thursday, April 17, 2014 9:56 AM
    Wednesday, April 9, 2014 1:15 PM

All replies

  • Hi,

    In this scenario, you should be using "ordinal comparison" as it looks purely at the values of the raw byte(s) that represent the character.

    This should work:

                var list = new List<string> { "@123", "@abc", "12234", "23", "test1" };
                list.Sort(StringComparer.Ordinal); 
    Please find more information about string comparison here.

    • Proposed as answer by Venkat786 Tuesday, April 8, 2014 9:51 PM
    • Unproposed as answer by Dharmendra Kumar Friday, April 11, 2014 1:19 PM
    Tuesday, April 8, 2014 7:52 PM
  • But as per my requirement , I want the sorting to be Numbers -> Special Chars ->Alphabets

    The above result should come as 

    "12234","23","@123","@abc","test1"


    Just be aware that when sorting strings the order will not reflect the *values* such as
    numeric order of any numbers represented. For example, given "15" and "123" then "123"
    will come before "15" in ascending order. Because the comparison will stop as soon as
    the 5 and 2 are compared. If you wanted the numeric order of the values represented in
    the strings (e.g. - 15 is less than 123) then you would have to do additional work.

    - Wayne


    • Edited by WayneAKing Tuesday, April 8, 2014 11:12 PM
    • Marked as answer by Caillen Thursday, April 17, 2014 9:56 AM
    Tuesday, April 8, 2014 11:06 PM
  • I wrote this.  It uses a LexicographicalComparison to compare strings according to their elements.  And it uses a ClassifiedComparison to compare characters first based on their classification.

    Then I provided a classification function that identifies numbers, alphabetical characters and special chars, as an enumertion, which in turn controls the collating order.

    Here's my example:

    class Program
    {
        /// <summary>
        /// Compares two sequences lexicographically based on the ordering of their elements.
        /// In the case that the elements are equal, the next elements in the sequence are compared.
        /// Non-existent elements precede existing elements.  e.g.:  "ab" &lt; "abc"
        /// For example: compares strings by comparing their chars.
        /// </summary>
        /// <typeparam name="T">The type of the elements of the sequences.</typeparam>
        /// <param name="componentComparison">A user-provided comparison function that
        /// compares elements.</param>
        /// <returns>a = b : 0; a &lt; b : -1; a &gt; b : 1</returns>
        static int LexicographicalComparison<T>(
            IEnumerable<T> a, IEnumerable<T> b,
            Comparison<T> componentComparison )
        {
            // Lexicographical comparison
            IEnumerator<T> ca = a.GetEnumerator();
            IEnumerator<T> cb = b.GetEnumerator();
            while( true ) {
                if( !ca.MoveNext() )
                    if( !cb.MoveNext() ) return 0;
                    else return -1;
                if( !cb.MoveNext() ) return 1;
                int result = componentComparison( ca.Current, cb.Current );
                if( result == 0 ) continue;
                return result;
            }
        }
    
        /// <summary>
        /// Compares items first according to their classification, then according to the
        /// items themselves.
        /// </summary>
        /// <typeparam name="T">The type of the items themselves.</typeparam>
        /// <typeparam name="C">The type of the classification of the items.</typeparam>
        /// <returns>a = b : 0; a &lt; b : -1; a &gt; b : 1</returns>
        static int ClassifiedComparison<T, C>(
            T a, T b,
            Func<T, C> classifier )
            where C : IComparable
            where T : IComparable
        {
            int itemCompare = a.CompareTo( b ); // Assume identical items have identical classifications.
            if( itemCompare == 0 ) return 0;
            int classCompare = classifier( a ).CompareTo( classifier( b ) );
            if( classCompare == 0 ) return itemCompare;
            return classCompare;
        }
    
        enum CharClass
        {
            // The order you put these enums in determines the collating order
            Numbers,
            Special,
            Alphabets,
        }
    
        static CharClass GetCharClass( char c )
        {
            if( char.IsDigit( c ) ) return CharClass.Numbers;
            if( char.IsLetter( c ) ) return CharClass.Alphabets;
            return CharClass.Special;
        }
    
        static void Main( string[] args )
        {
            List<string> words = new List<string>() { "Test1", "12234", "23", "@abc", "@123" };
            words.Sort( ( a, b ) => LexicographicalComparison<char>( a, b,
                ( x, y ) => ClassifiedComparison( x, y, GetCharClass ) ) );
            Console.WriteLine( string.Join( ", ", words ) );
        }
    }
    

    • Marked as answer by Caillen Thursday, April 17, 2014 9:56 AM
    Wednesday, April 9, 2014 1:15 PM