У меня есть отсортированный набор с моей структурой данных, которая содержит идентификатор (строку) и дату. Я хочу избежать дублирования с использованием идентификатора и отсортировать элементы в наборе по дате, поэтому я сделал свою структуру данных, реализующую интерфейс IComparable<T>
таким образом:
public class PreLobbyPlayer : IComparable<PreLobbyPlayer>
{
public int CompareTo(PreLobbyPlayer other)
{
// First avoid duplicate players
int compResult = this.SPlayerId.CompareTo( other.SPlayerId);
if ( compResult == 0 )
return compResult;
// Then compare join dates
compResult = this.DJoinDate.CompareTo(other.DJoinDate);
// If dates are equal, get the first, but we don't
// prevent insertion of two different players with the same date
return compResult == 0 ? -1 : compResult;
}
}
Затем я пытаюсь удалить один элемент, используя идентификатор с помощью метода LINQ RemoveWhere(p => p.SPlayerId == sPlayerId)
, где sPlayerId
— это идентификатор, указанный в другом месте кода.
Дело в том, что иногда элемент не удаляется, RemoveWhere(...)
возвращает 0 и элемент все еще находится в SortedSet<PreLobbyPlayer>
Я кодирую некоторую отладочную информацию, и вот результат:
jor0|jor11|jor12|jor8|jor5|jor14|jor9|jor3|jor13|jor15|jor10|jor7|jor4|jor1|jor2|
Leave for user jor6, playerCount is: 15, removed is 1, prevSOwnerPlayerId is jor0
jor0|jor11|jor12|jor8|jor5|jor14|jor9|jor13|jor3|jor10|jor15|jor4|jor7|jor1|jor2|
Leave for user jor7, playerCount is: 15, removed is 0, prevSOwnerPlayerId is jor0
jor0|jor11|jor12|jor8|jor14|jor9|jor13|jor3|jor10|jor15|jor4|jor7|jor1|jor2|
Leave for user jor5, playerCount is: 14, removed is 1, prevSOwnerPlayerId is jor0
jor0|jor11|jor12|jor8|jor14|jor9|jor3|jor13|jor15|jor10|jor7|jor1|jor2|
Leave for user jor4, playerCount is: 13, removed is 1, prevSOwnerPlayerId is jor0
jor0|jor12|jor8|jor14|jor9|jor13|jor3|jor10|jor15|jor7|jor1|jor2|
Leave for user jor11, playerCount is: 12, removed is 1, prevSOwnerPlayerId is jor0
jor0|jor12|jor8|jor14|jor9|jor3|jor13|jor15|jor10|jor7|jor1|
Leave for user jor2, playerCount is: 11, removed is 1, prevSOwnerPlayerId is jor0
jor0|jor12|jor8|jor14|jor9|jor13|jor3|jor10|jor15|jor7|jor1|
Leave for user jor15, playerCount is: 11, removed is 0, prevSOwnerPlayerId is jor0
jor0|jor8|jor14|jor9|jor13|jor3|jor10|jor15|jor7|jor1|
Leave for user jor12, playerCount is: 10, removed is 1, prevSOwnerPlayerId is jor0
jor0|jor8|jor14|jor9|jor3|jor13|jor15|jor10|jor7|
Leave for user jor1, playerCount is: 9, removed is 1, prevSOwnerPlayerId is jor0
jor0|jor8|jor9|jor13|jor3|jor10|jor15|jor7|
Leave for user jor14, playerCount is: 8, removed is 1, prevSOwnerPlayerId is jor0
jor8|jor9|jor3|jor13|jor15|jor10|jor7|
Leave for user jor0, playerCount is: 7, removed is 1, prevSOwnerPlayerId is jor0
jor8|jor13|jor3|jor10|jor15|jor7|
Leave for user jor9, playerCount is: 6, removed is 1, prevSOwnerPlayerId is jor8
jor8|jor3|jor13|jor15|jor10|jor7|
Leave for user jor10, playerCount is: 6, removed is 0, prevSOwnerPlayerId is jor8
jor8|jor13|jor15|jor10|jor7|
Leave for user jor3, playerCount is: 5, removed is 1, prevSOwnerPlayerId is jor8
jor8|jor10|jor15|jor7|
Leave for user jor13, playerCount is: 4, removed is 1, prevSOwnerPlayerId is jor8
jor15|jor10|jor7|
Leave for user jor8, playerCount is: 3, removed is 1, prevSOwnerPlayerId is jor8
список идентификаторов "jorxx" - это печать всех идентификаторов элементов SortedSet после вызова RemoveWhere. remove — это значение, возвращаемое RemoveWhere, playerCount — это длина SortedSet после вызова RemoveWhere, «Leave for user» указывает идентификатор удаленного элемента, а остальные можно игнорировать.
Как видите, в этом случае элементы с идентификаторами jor15, jor7 и jor10 не удаляются, хотя они присутствуют в SortedSet. Каждый раз, когда я пытаюсь, порядок вставки и даты меняются, поэтому другие элементы не работают. Даже бывают случаи, когда все элементы успешно удаляются. Я предполагаю, что если я буду использовать тот же порядок вставки и даты, результаты будут такими же, но мне нужно слишком сильно изменить код, чтобы проверить его. Да, я ленивый ;)
Я заставил его работать, изменив функцию CompareTo на:
return this.SPlayerId.CompareTo(other.SPlayerId);
и упорядочивание с помощью DJoinDate с использованием OrderBy, когда это необходимо, но я хотел бы знать, почему моя прежняя реализация CompareTo нарушает логику SortedSet.
Редактировать:
Как указал PetSerAl, мой метод CompareTo не давал согласованных результатов, когда даты считались равными.
Я изменил CompareTo на:
public class PreLobbyPlayer : IComparable<PreLobbyPlayer>
{
public int CompareTo(PreLobbyPlayer other)
{
// First avoid duplicate players
int compIdResult = this.SPlayerId.CompareTo( other.SPlayerId);
if ( compIdResult == 0 )
return compIdResult;
// Then compare join dates
int compDateResult = this.DJoinDate.CompareTo(other.DJoinDate);
// If dates are equal, return the id comparison result to give consistent results.
return compDateResult == 0 ? compIdResult : compDateResult;
}
}
и работал как шарм. Спасибо.
Редактировать:
Как снова указал @PetSerAl :), моя вторая версия метода CompareTo для класса PreLobbyPlayer по-прежнему дает противоречивые результаты. Вы можете следить за объяснением в принятом ответе и его комментариях. По сути, вы можете закончить с SortedSet, содержащим PreLobbyPlayers с тем же идентификатором, и это нехорошо для меня. SortedSet использует ту же логику упорядочения, чтобы избежать дублирования и может опустить некоторые сравнения между элементами (я не жалуюсь на реализацию SortedSet, она нормальная и эффективная). Я не смог найти последовательную реализацию CompareTo (PreLobbyPlayer other) для этого случая, идеи и предложения приветствуются.
Мое окончательное решение использует только идентификатор, чтобы избежать дублирования и упорядочить набор, используя дату и метод LINQ OrderBy, когда это необходимо. Для меня это приемлемо, потому что SortedSet будет содержать не более 100 элементов и в логике есть только один случай, когда мне нужна коллекция, упорядоченная по дате.
public class PreLobbyPlayer : IComparable<PreLobbyPlayer>
{
public int CompareTo(PreLobbyPlayer other)
{
return this.SPlayerId.CompareTo( other.SPlayerId);
}
...
}