treeSet 一个很诡异的重复性判断问题

问题描述

有一个需求是这样的,要求去掉重复Id的文章,如果id相同就去掉,如果不同就按文章发表时间排序,但写完代码发现,id相同的文章怎么也去重不了:public class ArticleSource implements Comparable<ArticleSource> {private long id;private int sourceId;private long time;public ArticleSource(long id,int sourceId,long time) {this.id = id;this.sourceId = sourceId;this.time = time;;}public long getId() {return id;}public void setId(long id) {this.id = id;}public int getSourceId() {return sourceId;}public void setSourceId(int sourceId) {this.sourceId = sourceId;}public long getTime() {return time;}public void setTime(long time) {this.time = time;}@Overridepublic boolean equals(Object obj) {System.out.println("equals");if(obj instanceof ArticleSource) {ArticleSource at = (ArticleSource)obj;if(at.getId() == this.getId()) {return true;}}return false;}@Overridepublic int hashCode() {System.out.println("hash"); return (int) id;}@Overridepublic int compareTo(ArticleSource o) {if(o == null) {return 0;}System.out.println(o.getId() + "=>"+this.getId() );if(o.getId() == this.getId()) {return 0;}if(o.getTime() >this.getTime()) {return -1;}else if(o.getTime()==this.getTime()){return 0;}else {return 1;}}@Overridepublic String toString() {return id +":" + time;}public static void main(String[] args) {Set<ArticleSource> set = new TreeSet<ArticleSource>();set.add(new ArticleSource(391454L, 1420, 13626506898983L));set.add(new ArticleSource(3914064L, 1420, 10000L));set.add(new ArticleSource(3914065L, 4235, 1362650633576L));set.add(new ArticleSource(3914064L, 4235, 1363333333333L));System.out.println(set);}结果:391454=>3914064391454=>39140653914064=>39140653914065=>3914064391454=>3914064[3914064:10000, 3914065:1362650633576, 3914064:1363333333333, 391454:13626506898983]诡异的是,第二个和第四个id是相同的,竟然无法去重,更诡异的是,把第四个的time 少一位,就是136333333333L,又可以去掉重复,请教一下,是什么原因?难道long不允许超过13位吗结果:391454=>3914064391454=>39140653914064=>39140653914065=>39140643914064=>3914064[3914064:10000, 3914065:1362650633576, 391454:13626506898983]

解决方案

将compareTo方法改成public int compareTo(Object o1) {ArticleSource o = (ArticleSource)o1;int result = this.getId() > o.getId() ? 1 : (this.getId() == o.getId() ? 0 : -1);if (result == 0) { result = this.getId() > o.getId() ? 1 : (this.getId() == o.getId() ? 0 : -1); }return result;}其实你写的那个compareTo方法是有问题,举个很简单的例子,假如你main里面只有这三条数据set.add(new ArticleSource(2L, 1000, 10l));set.add(new ArticleSource(1L, 1000, 5l));set.add(new ArticleSource(1L, 1000, 30l));你会发现相同id的也没去掉当执行第二行的时候去compareTo方法,那么变成了1:52:101:30执行第三行的时候“1:30”只与“2:10”对比,未与“1:5”对比
解决方案二:
很明显你写的比较器,没有符合数学上的一些要求。比如:若A > B, C = A则A > B;这个就是所谓的可传递性吧(也不确切)。在你的例子里,根据你的比较器逻辑有:结点(3914064:10000) < 结点(3914065:1362650633576) 且 结点(3914064:10000)= 结点(3914064:1363333333333)这样根据数学要求应该有:结论1: 结点(3914064:1363333333333) < 结点(3914065:1362650633576)但是根据你的比较器逻辑又有:结论2:结点(3914064:1363333333333) > 结点(3914065:1362650633576)显然结论1和结论2是相矛盾的。故我想你的比较器逻辑本身就是有问题。
解决方案三:
上面的对比算法是有问题的, 没有考虑到如果时间相同、但id不同的情况。。 按照lz写的算法,如果时间相同,但id不同的数据会认为是相等的。就会出现如下的情况ArticleSource b = new ArticleSource(1, 1, 13); //a=bArticleSource c = new ArticleSource(2, 1, 12); //a=c , b>cArticleSource d = new ArticleSource(2, 1, 13); //d=c即a=b, a=c 但是b<> c 的情况,可以调整的方式就是简单对时间相同,但id不同的情况做处理既可了:public int compareTo(ArticleSource o) {if (o == null) {return 0;}System.out.println(o.getId() + "=>" + this.getId());if (o.getId() == this.getId()) {return 0;}if (o.getTime() > this.getTime()) {return -1;} else if (o.getTime() == this.getTime()) {return o.getId()>this.getId()?1:-1;} else {return 1;}}
解决方案四:
override hashCode and equals whenever the instance possibly will be placed in collection based on hash implementation. TreeSet不是基于hash的容器
解决方案五:
TreeSet的确很诡异,使用的时候需要很小心。关于无法去重的原因:TreeSet是根据compareTo方法来进行去重的,你的实现方式是根据id或者time来进行排序的,会导致不确定排序。set中添加元素的顺序不同,排序也不同。可以看下TreeSet的具体实现。
解决方案六:
treeset的使用要特别注意两个地方:排异性和比对性。但很多时候会发现很多人都会搞错,只实现了后者,而没有实现前者。其实问题就是在compareTo这个函数里。
解决方案七:
原因我倒是知道了。根源在你的compareTo方法中混合两个属性(id, time)进行排序。你跟踪下TreeSet的代码也能明白。TreeSet内部调用TreeMap的Put方法。简单的说,在Put时并不会遍历整个列表的,而是按照红黑树http://www.ibm.com/developerworks/cn/java/j-lo-tree/index.html你的例子就是寻找过程中,根据Time先找到了位置,于是就无视ID的比较。跟踪代码你会发现,在add最后那条数据时,就根本没去比较已有的3914064。同样的道理,如果你改变time的值引用把第四个的time 少一位,就是136333333333L会导致,已有的3914064参与比较,于是逻辑又好像对了。不知道我有没有说清楚。道理虽然明白了,我也没有好的解决办法。目前能想到的,只有先过滤掉重复ID,比如另加个Set。但这样实在丑陋。这个需求看似简单,实现起来比较麻烦,哈哈。
解决方案八:
at.getId() == this.getId() 改成 at.getId().equals(this.getId())

时间: 2024-09-23 07:58:12

treeSet 一个很诡异的重复性判断问题的相关文章

html-麻烦帮忙看一个很诡异的CSS高度设置的问题

问题描述 麻烦帮忙看一个很诡异的CSS高度设置的问题 我有一个html文件,把一个div元素高度设置为45px,如果把文件直接拖到浏览器,这个div是正常的45px.但是如果是通过服务器访问,即localhost:8080/webroot/myhtml.html这样的形式访问,则这个div是46px,并且只会在谷歌出现这个问题更奇葩的是,只有最后一个数字是5的时候才出现问题,例如我设置为44px,53px是正常的,但是如果设置为45px,55px,65px就出问题了,下面是我的完整代码 <!DO

多对一-Hibernate上一个很诡异的问题

问题描述 Hibernate上一个很诡异的问题 User.hbm.xml: <set cascade="all" inverse="true" name="activeFriends" sort="unsorted"> <key column="concernedUserId"/> <one-to-many class="Friends"/> <

使用apache的BeanUtils,一个很诡异的问题

问题描述 public class MyBeanUtils extends org.apache.commons.beanutils.BeanUtils {public static void copyBeanNotNull2Bean(Object databean,Object tobean)throws Exception { PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(databea

boolean-问一个很白的问题:关于if中Boolean判断的

问题描述 问一个很白的问题:关于if中Boolean判断的 Boolean flag;if(flag) i = 1;} else { i = 2;}我的flag的值是从别的类中传过来的,那么,当我flag=true时我的i=1还是i = 2:当我flag=false时i=1还是i= 2? 解决方案 一般 false 由0代替,true 是非0,有用1的,也有用-1的.所以flag=true时,是i=1: flag=false时,是i=2 解决方案二: C++中异常处理与if判断的问题判断一个整数

java-用eclipse安卓开发时遇到的一个十分诡异的问题

问题描述 用eclipse安卓开发时遇到的一个十分诡异的问题 @Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String filePath = ""/storage/sdcard0/DCIM/Camera/20130826_182939.jpg"&q

c语言 单片机-keil4开发中遇到的一个很奇怪的问题。

问题描述 keil4开发中遇到的一个很奇怪的问题. void main(){ // uchar test_i; const uchar timp_button=0xfF; //this value is that the button havn't sticked uchar n_delay; //delay unsigned char j=0; unsigned char i; intend_initiation(); //调用时间设定程序 while(1){ if((hour==alarm_

用火狐下载文件出现很诡异的问题

问题描述 用火狐下载文件出现很诡异的问题 在csdn上下载文件 文件后缀名总是自动多出一个'_' 更奇怪的是 下载下来会有两个同名文件 其中一个是空文件 删除空文件后缀名还会报错 说此文件不在这个路径下 无法执行删除操作 不知道这个是怎么了 就是在csdn上下载东西会出现这个问题 解决方案 这个我也遇到过,你下载完后,对文件夹重新命名,把最后字符下划线去掉,不影响你对rar文件的使用.谢谢 解决方案二: 删除空文件没有作用 说找不到这个文件的位置 解决方案三: 这是火狐浏览器的问题,应该是在下载

编程-一个很简单的turbo c课堂复习试题的求解

问题描述 一个很简单的turbo c课堂复习试题的求解 turbo c中编程实现对回文数的判断,比如12321,就是一个回文数. 解决方案 #include <stdio.h> int rev(int n, int acc) { if (n == 0) return acc; return rev(n / 10, acc * 10 + n % 10); } int main() { int x = 1230321; int y = rev(x, 0); printf("%sn&quo

canvas和setInterval很诡异的问题

问题描述 canvas和setInterval很诡异的问题 本人萌新,写了一个关于canvas扇形图的动画效果,但是setInterval执行的时候很诡异的只有 第三次才能执行代码,看了半天也不知道哪里出错了,请大神们帮帮忙,感激不尽!! 代码如下,三个框框里面可以输入数字表示百分比 <!DOCTYPE html> <html> <head> <title>扇形图动态效果</title> <meta http-equiv="con