Используйте собственный IComparer <T> с Linq OrderBy

Сначала давайте посмотрим на определение оператора ===. Это не просто проверка равенства между значениями двух экземпляров, но проверка того, указывают ли две переменные на точно такой же экземпляр объекта ( см. «Операторы идентификации» здесь ).

Итак, ваш пример кода не совсем верен:

var a1 = A()
var a2 = A()
var a3 = a2
a1 === a2     // actually false, a1 and a2 were instantiated separately
a2 === a3     // true, because they are the same instance

Таким образом можно сравнивать только классы, потому что все, что не является классом в Swift, имеет типизированный тип * и два значения. переменные могут не указывать на один и тот же экземпляр.

Поэтому, если вы попытаетесь сравнить обычный протокол с ===, у Swift недостаточно информации для использования оператора. Экземпляры, которые вы сравниваете (p1 и p2), могут быть экземплярами класса, или они могут быть экземплярами структуры, и во время компиляции Swift не может определить, все ли в порядке.

Если вы хотите иметь возможность использовать протокол в качестве типа таким образом и сравнивать с ===, вам нужно объявить протокол только для класса следующим образом: используя class в качестве первого элемента в списке наследования вашего протокола, например:

protocol P : class {
}

class A : P {
}

Теперь вы можете делать то, что пытались, без ошибки компилятора:

var p1:P = a1
var p2:P = a2
var p3:P = a3
p1 === p2    // false
p2 === p3    // true

* Семантически, в любом случае. Swift выполняет много закулисной типизации ссылок, но применяет это типизированное поведение со значениями, поэтому для целей этого обсуждения просто перейдите к struct и enum по-настоящему типизированным значениям.

32
задан Mrchief 24 June 2013 в 01:21
поделиться

3 ответа

Ваш компаратор мне кажется неправильным. Вы все еще просто выполняете сортировку в порядке текста по умолчанию. Конечно, вы хотите проанализировать два числа и отсортировать их на основе этого:

public int Compare(Object stringA, Object stringB)
{
    string[] valueA = stringA.ToString().Split('/');
    string[] valueB = stringB.ToString().Split('/');

    if (valueA.Length != 2 || valueB.Length != 2)
    {
        stringA.ToString().CompareTo(stringB.ToString());
    }

    // Note: do error checking and consider i18n issues too :)
    if (valueA[0] == valueB[0]) 
    {
        return int.Parse(valueA[1]).CompareTo(int.Parse(valueB[1]));
    }
    else
    {
        return int.Parse(valueA[0]).CompareTo(int.Parse(valueB[0]));
    }
}

(Обратите внимание, что это не согласуется с вашим вопросом о том, что вы выполнили отладку и подтвердили, что Compare возвращает правильное значение, но я ' Боюсь, я подозреваю, что здесь произошла человеческая ошибка.)

Кроме того, Свен прав - изменение значения элементов вообще не меняет ваш связанный список. Вы должны добавить:

this.Items = items;

внизу вашего метода.

17
ответ дан 27 November 2019 в 21:06
поделиться

Отсортированный список привязан только к элементам локальной переменной, а не к свойству Items вашего списка привязки, поэтому он остается несортированным.

[Edit] По сути, вы просто выбрасываете результат своих усилий по сортировке; -)

2
ответ дан 27 November 2019 в 21:06
поделиться

Я столкнулся с проблемой общей естественной сортировки и написал решение здесь:

Natural Sort Сравните с Linq OrderBy ()

public class NaturalSortComparer<T> : IComparer<string>, IDisposable
{
    private bool isAscending;

    public NaturalSortComparer(bool inAscendingOrder = true)
    {
        this.isAscending = inAscendingOrder;
    }

    #region IComparer<string> Members

    public int Compare(string x, string y)
    {
        throw new NotImplementedException();
    }

    #endregion

    #region IComparer<string> Members

    int IComparer<string>.Compare(string x, string y)
    {
        if (x == y)
            return 0;

        string[] x1, y1;

        if (!table.TryGetValue(x, out x1))
        {
            x1 = Regex.Split(x.Replace(" ", ""), "([0-9]+)");
            table.Add(x, x1);
        }

        if (!table.TryGetValue(y, out y1))
        {
            y1 = Regex.Split(y.Replace(" ", ""), "([0-9]+)");
            table.Add(y, y1);
        }

        int returnVal;

        for (int i = 0; i < x1.Length && i < y1.Length; i++)
        {
            if (x1[i] != y1[i])
            {
                returnVal = PartCompare(x1[i], y1[i]);
                return isAscending ? returnVal : -returnVal;
            }
        }

        if (y1.Length > x1.Length)
        {
            returnVal = 1;
        }
        else if (x1.Length > y1.Length)
        { 
            returnVal = -1; 
        }
        else
        {
            returnVal = 0;
        }

        return isAscending ? returnVal : -returnVal;
    }

    private static int PartCompare(string left, string right)
    {
        int x, y;
        if (!int.TryParse(left, out x))
            return left.CompareTo(right);

        if (!int.TryParse(right, out y))
            return left.CompareTo(right);

        return x.CompareTo(y);
    }

    #endregion

    private Dictionary<string, string[]> table = new Dictionary<string, string[]>();

    public void Dispose()
    {
        table.Clear();
        table = null;
    }
}
10
ответ дан 27 November 2019 в 21:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: