How to use a custom Comparer to sort an Array in a different lexical order?
Asked Answered
M

3

7

So, I'm pretty new to C# and I'm trying to order an Array using a custom Comparer.

I created a class:

class MySorter : IComparer
{
    public int Compare(object x, object y)
    {
        var chars = "jngmclqskrzfvbwpxdht";
        if (chars.IndexOf((char)x) < chars.IndexOf((char)y))
            return -1;
        return chars.IndexOf((char)x) > chars.IndexOf((char)y) ? 1 : 0;
    }
}

And I have a Array full of words. How exacly I can use this Compare to sort?

Mossberg answered 14/2, 2016 at 17:24 Comment(0)
A
9

I think that what you need is this. Declare a method for sorting as you already did.

public static int CompareStrings(string s1, string s2)
{
    // TODO: your code here
}

... and specify what function you need to use.

string[] myStrings = { ... };
Array.Sort(myStrings, CompareStrings);

If you use generic classes, you can achieve this as well doing as it follows:

List<string> myStrings = ...;
myStrings.Sort(CompareStrings);
Anti answered 14/2, 2016 at 17:28 Comment(4)
Ok, now I can use my method, but I'm getting an InvalidCastException here: if (chars.IndexOf((char)x) < chars.IndexOf((char)y)) any idea why?Mossberg
x is either an object or a string so you need to cast it as a char, not with (char)x but Convert.ToChar(x)Anti
I tried it before, but then I got a 'System.FormatException'. I think that is happening because I have the whole string there. e.g "gmxz". Do I need to substring my string and get just the first char before comparing?Mossberg
Not necessarily. You can compare strings as well, but use the Equals() method. Well, if you have a string, you can't convert it into a char, you need to either pas char by char, or pass the entire string and compare strings, not chars.Anti
S
1

To answer this question for people wishing to use Linq the solution would be:

IEnumerable<string> words = new [] {"foo", "bar"};
words = words.OrderBy(x => x, new MySorter());

Note therefore that you should be using the generic interface for your comparer:

class MySorter : IComparer<string>
{
    public int Compare(string x, string y)
    {

    }
}

You can then use Linq to sort even objects:

IEnumerable<Person>  people = new []
{
    new Person
    {
        Name = "Matthew"
    },
    new Person
    {
        Name = "Mark"
    }
};
people = people.OrderBy(x => x.Name, new MySorter());

An important note relating to some of the issues you highlighted under Simply Me's answer:

Using the generic interface is always preferable when the types being compared are known, as amongst other things this would have alerted you at compile time rather than run time (when you got an InvalidCastException) that if you are sorting an array of words, assuming a word is a string, the IComparer you are implementing is not fit for purpose as it is comparing two char types.

(From what I am inferring by looking at your code, I think what you need to do is implement IComparer<string> and in the Compare method iterate through each char of both strings until they differ, and then use your char comparison logic - but, you should also consider how you handle uppercase and lowercase, what you do when one or both characters are not in your list and if one string in its entirety matches the first part of the other string, such as match and matches.)

Smithers answered 13/1, 2019 at 12:47 Comment(0)
F
0

An inline solution with an anonymous function. It will sort your strings in lexicographical order.

Array.Sort(arr, (a, b) => string.CompareOrdinal(a, b));

It will turn

var arr = new[] { "orange", "banana", "apple", "watermelon", "tomato" };

into

string[5] { "apple", "banana", "orange", "tomato", "watermelon" }
Faruq answered 15/8, 2023 at 15:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.