Сортировка объектов по правильности строки, пустая строка последняя - PullRequest
0 голосов
/ 18 октября 2018

У меня есть массив объектов, которые все содержат строковое свойство.Я хочу отсортировать объекты по строковому свойству в алфавитном порядке так, чтобы объекты с пустым строковым свойством попадали в конец списка.В настоящее время у меня есть это:

switches = switches.OrderBy(n => n.GetCurrentUser()).ToArray();

Проблема в том, что он помещает пустые строки в верхней части списка.Как поместить объекты со строками со значением (отсортированными по алфавиту) вверху и объекты с пустыми строками внизу?

Ответы [ 3 ]

0 голосов
/ 18 октября 2018

OrderBy имеет перегрузку, принимает IComparer <> T .Это позволяет вам определять свои собственные правила сортировки.Вы можете начать с универсального класса Comparer и переопределить метод Compare, например:

public class EmptyLastComparer: Comparer<string>
{
    public override int Compare(string x, string y)
    {
        if (String.IsNullOrWhiteSpace(x) && !String.IsNullOrWhiteSpace(y))
        {
            return 1;
        }
        else if (String.IsNullOrWhiteSpace(x) && String.IsNullOrWhiteSpace(y))
        {
            return 0;
        }
        else if (!String.IsNullOrWhiteSpace(x) && String.IsNullOrWhiteSpace(y))
        {
            return -1;
        }
        else
        {
            return x.CompareTo(y);
        }
    }
}

Чтобы использовать его, создайте новый экземпляр EmptyLastComparer () и передайте его OrderBy:

var myStrings = new[] { "c", "A","a", "A","b", " ","   ",null };
var ordered=myStrings.OrderBy(x => x, new EmptyLastComparer());

Сравнение строк сложнее, чем сравнение двух строк. String.Compare имеет перегрузки, которые допускают сравнение без учета регистра, использование определенных культур и т. Д. Пользовательский компаратор может принять параметр StringComparison в своем конструкторе, чтобы разрешить нечто подобное, например:

public class EmptyLastComparer : Comparer<string>
{
    private readonly StringComparison _comparison;

    public EmptyLastComparer(StringComparison comparison=StringComparison.CurrentCulture)
    {
        _comparison = comparison;
    }
    public override int Compare(string x, string y)
    {
        if (String.IsNullOrWhiteSpace(x) && !String.IsNullOrWhiteSpace(y))
        {
            return 1;
        }
        else if (String.IsNullOrWhiteSpace(x) && String.IsNullOrWhiteSpace(y))
        {
            return 0;
        }
        else if (!String.IsNullOrWhiteSpace(x) && String.IsNullOrWhiteSpace(y))
        {
            return -1;
        }
        else
        {
            return String.Compare(x,y, _comparison);
        }
    }
}

Возможно, даже добавить несколько предопределенных компараторов, как это делает StringComparer:

    public static EmptyLastComparer CurrentCulture =>
            new EmptyLastComparer();
    public static EmptyLastComparer CurrentCultureIgnoreCase => 
            new EmptyLastComparer(StringComparison.CurrentCultureIgnoreCase);

    public static EmptyLastComparer InvariantCulture =>
            new EmptyLastComparer(StringComparison.InvariantCulture);
    public static EmptyLastComparer InvariantCultureIgnoreCase =>
            new EmptyLastComparer(StringComparison.InvariantCultureIgnoreCase);

    public static EmptyLastComparer Ordinal =>
            new EmptyLastComparer(StringComparison.Ordinal);
    public static EmptyLastComparer OrdinalIgnoreCase =>
            new EmptyLastComparer(StringComparison.OrdinalIgnoreCase);

И использовать их таким же образом, не выделяя каждый раз новый компаратор:

var ordered=myStrings.OrderBy(x => x, EmptyLastComparer.InvariantCultureIgnoreCase);
0 голосов
/ 18 октября 2018

Вы также можете использовать встроенное создание Comparer:

switches.OrderBy(n => n.GetCurrentUser(),                
                Comparer<string>.Create((a, b) =>
                string.IsNullOrEmpty(a) && !string.IsNullOrEmpty(b)? 1 
                : !string.IsNullOrEmpty(a) && string.IsNullOrEmpty(b) ? -1 
                : string.Compare(a, b)));
0 голосов
/ 18 октября 2018

Вы можете использовать:

switches = switches
    .Select(n => new { TheObject = n, User = n.GetCurrentUser() })
    .OrderBy(x => String.IsNullOrEmpty(x.User) ? 1 : 0)
    .ThenBy(x => x.User)
    .Select(x => x.TheObject)
    .ToArray();

Сначала будут построены две группы: одна с пустым пользователем, а другие.OrderBy переместит их в конец, потому что 1 больше 0. Если вы хотите, чтобы они были сверху, используйте OrderByDescending.

Затем я использую ThenBy для сортировки по алфавиту, что будет иметь значение только для непустые пользователи.

...