我有一个带有我的数据结构的排序集,其中包含一个id(字符串)和一个日期。我想避免使用id重复,并使用日期将元素排序在集合中,所以我使我的数据结构以这种方式实现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)
的id删除一个元素,其中sPlayerId
是代码中其他地方指定的id。
事实是有时候元素没有删除,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
&#34; jorxx&#34;的列表ids是在调用RemoveWhere之后打印SortedSet元素的所有ID。 remove是RemoveWhere返回的值,playerCount是调用RemoveWhere后SortedSet的长度,&#34; Leave for user&#34;指定删除的元素的id,您可以忽略其余的。
正如您在本案中所看到的那样,尽管它们存在于SortedSet中,但不会删除带有id jor15,jor7和jor10的元素。每次我尝试时,插入顺序和日期都不同,因此其他元素都会失败。甚至有时会成功删除所有元素。我想如果我将使用相同的插入顺序和日期,结果将是相同的但我必须更改代码太多以测试它。是的,我懒惰;)
我让它将CompareTo函数更改为:
return this.SPlayerId.CompareTo(other.SPlayerId);
并在需要时使用OrderBy由DJoinDate排序,但我想知道为什么我之前的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再次指出:),我的PreLobbyPlayer类的CompareTo方法的第二个版本仍然给出不一致的结果。您可以按照接受的答案及其评论中的说明进行操作。基本上,您可能会使用包含具有相同ID的PreLobbyPlayers的SortedSet结束,这对我不利。 SortedSet使用相同的排序逻辑来避免重复,并且可以省略元素之间的一些比较(我不抱怨SortedSet实现,它是正常和有效的)。我无法为这个案例找出一致的CompareTo(PreLobbyPlayer其他)实现,欢迎提出想法和建议。
我的最终解决方案是仅使用id来避免重复,并在需要时使用日期和LINQ的OrderBy方法对集合进行排序。对我来说,这是可以接受的,因为SortedSet将包含不超过100个元素,并且当我需要按日期排序的集合时,逻辑中只有一个案例。
public class PreLobbyPlayer : IComparable<PreLobbyPlayer>
{
public int CompareTo(PreLobbyPlayer other)
{
return this.SPlayerId.CompareTo( other.SPlayerId);
}
...
}
答案 0 :(得分:0)
如果日期相同,请先获得,但我们不会 防止插入两个具有相同日期的不同玩家
什么是“第一”?请考虑以下两个示例:a.CompareTo(b)
和b.CompareTo(a)
。它们是否提供一致的结果?
您的CompareTo
还有其他不一致:a={Id1,DateA}
,b={Id2,DateB}
,c={Id1,DateC}
其中DateA<DateB<DateC
。使用您的代码,您将拥有:a<b
,b<c
和a=c
。因此,您的CompareTo
实施并不总是阻止向SPlayerId
添加具有相同SortedSet
的两个元素。
var a=new PreLobbyPlayer { SPlayerId=1,DJoinDate=DateTime.Today };
var b=new PreLobbyPlayer { SPlayerId=2,DJoinDate=DateTime.Today.AddDays(1) };
var c=new PreLobbyPlayer { SPlayerId=1,DJoinDate=DateTime.Today.AddDays(2) };
var set=new SortedSet<PreLobbyPlayer>();
set.Add(b);
set.Add(a);
set.Add(c);
foreach(var current in set) {
Console.WriteLine("{0}: {1}",current.SPlayerId,current.DJoinDate);
}
答案 1 :(得分:0)
如果正在比较2 PreLobbyPlayer
个具有相同DJoinDate
(但不同的id&#39; s)的对象a和b,则比较结果是随机的。
取决于哪一个&#39;这个&#39;哪一个是&#39;其他&#39;有时a会比b大,有时b会比a大。
如果DJoinDate
相同,您可以只比较ID,这样订单总是一样的。
public int CompareTo(PreLobbyPlayer other)
{
// First avoid duplicate players
int idCompare = this.SPlayerId.CompareTo(other.SPlayerId);
if (idCompare == 0) return 0;
// Then compare join dates
int dateCompare = this.DJoinDate.CompareTo(other.DJoinDate);
// If dates are equal, get the result from the first comparison
return dateCompare == 0 ? idCompare : dateCompare;
}