简体   繁体   中英

Change C# sorting behaviour

Lets say i have the strings abc_ and abc2_ . Now, normally when sorting i C# abc2_ would come after abc_ , leaving the result:

  1. abc_
  2. abc2_

I am using this to sort, if it matters:

     var element = from c in elements
     orderby c.elementName ascending
     select c;

How can i change this? I want abc_ to come last. Reversing is not an option because the list is contains more than two elements.

The OrderBy method can potentially take an IComparer<T> argument. (I'm not sure if that overload can be used with query comprehension syntax, or if it's only available when using the fluent extension method syntax.)

Since it's not clear exactly what your sort algorithm should involve, I'll leave implementing the required IComparer<T> as an exercise for the reader.

The simplest solution is to use the ordinal string comparer built in to the .NET Framework:

var element = from c in elements
    .OrderBy(c => c.elementName, StringComparer.Ordinal) 
    select c; 

No custom Comparer class needed!

If you want to underscore to play no part in the comparison, we can just make it so. So:

class CustomComparer : Comparer<string>
    {            
        public override int Compare(string a, string b)
        {   
            //Jamiec fixed the line below.             
            return a.Replace("_", "").CompareTo(b.Replace("_", ""));
        }
    }


var customComparer = new CustomComparer();                                    
var element = elements.OrderBy(c => c.elementName, customComparer);

I'm still unsure of the actual pattern we are trying to sort on but I wrote what I thought would be a solution. I saw "_" as a kind of wildcard where "abc2_" would be a subset of "abc_". But from the OPs comments "bar_" < "barxyz" breaks my understanding. Here's my code and I can modify when I gain more clarity.

static void Main(string[] args)
    {
        List<Element> Elements = new List<Element>();
        Elements.Add(new Element("abc_"));
        Elements.Add(new Element("abc2_"));
        Elements.Add(new Element("aaa"));

        var max = Elements.Max(e => e.Name.Length);
        var result = Elements.OrderBy(e => e.Name, new CustomComparer(max));

        foreach (var item in result)
            Console.WriteLine(item.Name);

        Console.Read();

    }

    class Element
    {
        public string Name { get; private set; }
        public Element(string name)
        {
            this.Name = name;
        }
    }

    class CustomComparer : Comparer<string>
    {
        private const string cWildCard = "_";
        private const char cHeavyChar = 'Z';
        public int Max { get; private set; }
        public CustomComparer(int max)
        {
            this.Max = max;
        }
        public override int Compare(string a, string b)
        {
            string comp1 = string.Empty, comp2 = string.Empty;

            int index = a.IndexOf(cWildCard);
            if (index > 0)
                comp1 = a.Substring(0, index).PadRight(this.Max, cHeavyChar);
            index = b.IndexOf(cWildCard);
            if (index > 0)
                comp2 = b.Substring(0, index).PadRight(this.Max, cHeavyChar);

            int result = comp1.CompareTo(comp2);
            return result;
        }
    }

You can see I'm just weighting a word heavier from where a "_" is found. Let me know if this is on the right track.

使用CompareOptions.Ordinal就可以了。

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