Сообщение Re: Ключ, взятый из коллекции ключей, отсутствует в словаре от 31.03.2022 8:28
Изменено 31.03.2022 8:41 xpalex
Re: Ключ, взятый из коллекции ключей, отсутствует в словаре
Здравствуйте, Воронин Иван, Вы писали:
Проблема тут:
ВИ>
Реализация SortedList использует массив для хранения элементов и свойство SortedList.Item[] использует бинарный поиск для получения индекса элемента в массиве.
gecnm
Соответственно, что бы дойти до существующего ключа бинарным поиском, нужна корректная реализация интерфейса System.IComparable (метод
Пусть есть ключи k1, k2, где k1 = TargetKey("3", "a", 1) и k2 = TargetKey("2", "b", 1))
k2.Compare(k1) == -1, т, к. оператор "<" вернет true в строке
и k1.Compare(k2) == -1, т, к. оператор "<" вернет true в строке
при добавлении в список первого ключа — он попадет в первую позицию списка (индекс 0),
при добавлении второго , т.к. k2 < k1 — k2 попадет в первую, а k1 переместится во вторую (индекс 1).
про попытыке найти элемент по ключу k1, будет взят ключ для сравнения из середины списка (индекс = floor(list.size/2) — 1 == 0), т.е. k2.
т.к. k1.CompareTo(k2) == -1, то алгоритм поиска попытается искать слева от индекса 0. Что и приводит к исключению.
Вообще референсным способом добавления операций сравнения является реализция кода сравнения в единственном месте (в методе CompareTo), а реализации операторов должны переиспользовать CompareTo. В вашем примере сделано наоборот (две реализации и обе некорректных) и из-за этого появилось нарушение контракта для реализации IComparable
Проблема тут:
ВИ>
ВИ> public static bool operator <(TargetKey a, TargetKey b)
ВИ> {
ВИ> if (a is null || b is null) return false;
ВИ> if (a._Code.CompareTo(b._Code) < 0) return true;
ВИ> if (a._Name.CompareTo(b._Name) < 0) return true;
ВИ> if (a._Level.CompareTo(b._Level) < 0) return true;
ВИ> return false;
ВИ> }
ВИ> public static bool operator >(TargetKey a, TargetKey b)
ВИ> {
ВИ> if (a is null || b is null) return false;
ВИ> if (a._Code.CompareTo(b._Code) > 0) return true;
ВИ> if (a._Name.CompareTo(b._Name) > 0) return true;
ВИ> if (a._Level.CompareTo(b._Level) > 0) return true;
ВИ> else return false;
ВИ> }
ВИ>
Реализация SortedList использует массив для хранения элементов и свойство SortedList.Item[] использует бинарный поиск для получения индекса элемента в массиве.
gecnm
Соответственно, что бы дойти до существующего ключа бинарным поиском, нужна корректная реализация интерфейса System.IComparable (метод
public int CompareTo(TargetKey compareTargetKey)
) для типа ключа.Пусть есть ключи k1, k2, где k1 = TargetKey("3", "a", 1) и k2 = TargetKey("2", "b", 1))
k2.Compare(k1) == -1, т, к. оператор "<" вернет true в строке
if (a._Code.CompareTo(b._Code) < 0) return true;
и k1.Compare(k2) == -1, т, к. оператор "<" вернет true в строке
if (a._Name.CompareTo(b._Name) > 0) return true;
при добавлении в список первого ключа — он попадет в первую позицию списка (индекс 0),
при добавлении второго , т.к. k2 < k1 — k2 попадет в первую, а k1 переместится во вторую (индекс 1).
про попытыке найти элемент по ключу k1, будет взят ключ для сравнения из середины списка (индекс = floor(list.size/2) — 1 == 0), т.е. k2.
т.к. k1.CompareTo(k2) == -1, то алгоритм поиска попытается искать слева от индекса 0. Что и приводит к исключению.
Вообще референсным способом добавления операций сравнения является реализция кода сравнения в единственном месте (в методе CompareTo), а реализации операторов должны переиспользовать CompareTo. В вашем примере сделано наоборот (две реализации и обе некорректных) и из-за этого появилось нарушение контракта для реализации IComparable
Re: Ключ, взятый из коллекции ключей, отсутствует в словаре
Здравствуйте, Воронин Иван, Вы писали:
Проблема тут:
ВИ>
Реализация SortedList использует массив для хранения элементов и свойство SortedList.Item[] использует бинарный поиск для получения индекса элемента в массиве.
Соответственно, что бы дойти до существующего ключа бинарным поиском, нужна корректная реализация интерфейса System.IComparable (метод
Пусть есть ключи k1, k2, где k1 = TargetKey("3", "a", 1) и k2 = TargetKey("2", "b", 1))
k2.Compare(k1) == -1, т, к. оператор "<" вернет true в строке
и k1.Compare(k2) == -1, т, к. оператор "<" вернет true в строке
при добавлении в список первого ключа — он попадет в первую позицию списка (индекс 0),
при добавлении второго , т.к. k2 < k1 — k2 попадет в первую, а k1 переместится во вторую (индекс 1).
про попытыке найти элемент по ключу k1, будет взят ключ для сравнения из середины списка (индекс = floor(list.size/2) — 1 == 0), т.е. k2.
т.к. k1.CompareTo(k2) == -1, то алгоритм поиска попытается искать слева от индекса 0. Что и приводит к исключению.
Вообще референсным способом добавления операций сравнения является реализция кода сравнения в единственном месте (в методе CompareTo), а реализации операторов должны переиспользовать CompareTo. В вашем примере сделано наоборот (две реализации и обе некорректных) и из-за этого появилось нарушение контракта для реализации IComparable
Проблема тут:
ВИ>
ВИ> public static bool operator <(TargetKey a, TargetKey b)
ВИ> {
ВИ> if (a is null || b is null) return false;
ВИ> if (a._Code.CompareTo(b._Code) < 0) return true;
ВИ> if (a._Name.CompareTo(b._Name) < 0) return true;
ВИ> if (a._Level.CompareTo(b._Level) < 0) return true;
ВИ> return false;
ВИ> }
ВИ> public static bool operator >(TargetKey a, TargetKey b)
ВИ> {
ВИ> if (a is null || b is null) return false;
ВИ> if (a._Code.CompareTo(b._Code) > 0) return true;
ВИ> if (a._Name.CompareTo(b._Name) > 0) return true;
ВИ> if (a._Level.CompareTo(b._Level) > 0) return true;
ВИ> else return false;
ВИ> }
ВИ>
Реализация SortedList использует массив для хранения элементов и свойство SortedList.Item[] использует бинарный поиск для получения индекса элемента в массиве.
Соответственно, что бы дойти до существующего ключа бинарным поиском, нужна корректная реализация интерфейса System.IComparable (метод
public int CompareTo(TargetKey compareTargetKey)
) для типа ключа.Пусть есть ключи k1, k2, где k1 = TargetKey("3", "a", 1) и k2 = TargetKey("2", "b", 1))
k2.Compare(k1) == -1, т, к. оператор "<" вернет true в строке
if (a._Code.CompareTo(b._Code) < 0) return true;
и k1.Compare(k2) == -1, т, к. оператор "<" вернет true в строке
if (a._Name.CompareTo(b._Name) < 0) return true;
при добавлении в список первого ключа — он попадет в первую позицию списка (индекс 0),
при добавлении второго , т.к. k2 < k1 — k2 попадет в первую, а k1 переместится во вторую (индекс 1).
про попытыке найти элемент по ключу k1, будет взят ключ для сравнения из середины списка (индекс = floor(list.size/2) — 1 == 0), т.е. k2.
т.к. k1.CompareTo(k2) == -1, то алгоритм поиска попытается искать слева от индекса 0. Что и приводит к исключению.
Вообще референсным способом добавления операций сравнения является реализция кода сравнения в единственном месте (в методе CompareTo), а реализации операторов должны переиспользовать CompareTo. В вашем примере сделано наоборот (две реализации и обе некорректных) и из-за этого появилось нарушение контракта для реализации IComparable