有一个顺序可以动态变化的Java比较器可以吗?

有一个顺序可以动态变化的Java比较器可以吗?,java,collections,comparator,Java,Collections,Comparator,我有一组时间戳值,我想放在一个排序集中 public class TimedValue { public Date time; public double value; public TimedValue(Date time, double value) { this.time = time; this.value = value; } } 对该集合进行排序的业务逻辑表明,值必须按降序排列,除非它比最新值早7天以上 因此,作为测

我有一组时间戳值,我想放在一个排序集中

public class TimedValue {
    public Date time;
    public double value;

    public TimedValue(Date time, double value) {
        this.time = time;
        this.value = value;
    }
}
对该集合进行排序的业务逻辑表明,值必须按降序排列,除非它比最新值早7天以上

因此,作为测试,我提出了以下代码

DateFormat dateFormatter = new SimpleDateFormat("MM/dd/yyyy");
TreeSet<TimedValue> mySet = new TreeSet<TimedValue>(new DateAwareComparator());
mySet.add(new TimedValue(dateFormatter.parse("01/01/2009"), 4.0 )); // too old
mySet.add(new TimedValue(dateFormatter.parse("01/03/2009"), 3.0)); // Most relevant
mySet.add(new TimedValue(dateFormatter.parse("01/09/2009"), 2.0));
DateFormat dateFormatter=新的SimpleDataFormat(“MM/dd/yyyy”);
TreeSet mySet=new TreeSet(new dateawarecomprator());
添加(新的TimedValue(dateFormatter.parse(“01/01/2009”),4.0));//太老了
添加(新的TimedValue(dateFormatter.parse(“01/03/2009”),3.0));//最相关
添加(新的TimedValue(dateFormatter.parse(“01/09/2009”),2.0);
如您所见,最初第一个值比第二个值更相关,但一旦将最终值添加到集合中,第一个值已过期,应该是最不相关的值

我的初步测试表明这应该有效。。。树集将在添加更多值时动态重新排列整个列表

但即使我看到了,我也不确定我是否相信

在添加每个元素时,已排序的集合是否会对整个集合重新排序?以这种方式使用排序集合(即性能)有什么困难吗?在添加了所有值之后手动排序列表是否更好(我猜是这样的)



跟进:
正如许多人(甚至我在某种程度上)所怀疑的那样,已排序的集合不支持这种“动态重新排序”方式。我相信我最初的测试完全是偶然的。当我向集合中添加更多元素时,“顺序”很快就崩溃了。感谢大家的积极响应,我对代码进行了重构,使用了许多人建议的方法。

我不相信JDK库甚至第三方库是为了处理结果不一致的比较器而编写的。我不指望这个能起作用。如果您的比较器在一次调用时可以返回两个值不相等的值,并且在以后调用时可以返回相同的两个值相等的值,我会更加担心

仔细阅读合同。您的比较器是否满足这些约束条件

更详细地说,如果您的比较器在调用一次时返回两个值不相等,但后来返回两个值相等,因为后来的值被添加到集合中并更改了比较器的输出,“集合”(无重复项)的定义将被撤消


乔恩·斯基特的回答是一个很好的建议,可以避免担心这些问题。确实,如果比较器没有返回与
equals()
一致的值,那么您可能会遇到大问题。每次添加内容时,排序后的集合是否会重新排序,这一点我并不确定,但如果更改顺序,最糟糕的情况是集合无法保持排序。

我99%确定这不会起作用。如果集合中的某个值突然改变其比较行为,则可能(实际上很可能)再也找不到该值;i、 e.
set.contains(值)
将返回
false
,因为搜索算法将在某一点进行比较,并在错误的子树中继续,因为该比较现在返回的结果与插入值时不同。

我认为比较器的不变性质应该是基于每种排序的,因此,只要您在给定排序操作的持续时间内保持一致,您就可以了(只要没有任何项目跨越7天的中间排序边界)

但是,您可能想让它更明显,您是在专门询问一个树集,我想当您添加一个新项目时,它会重复使用以前排序中的信息来节省时间,所以这是一个有点特殊的情况。TreeSet javadocs特别遵从Comparator语义,因此您可能没有得到官方支持,但您必须阅读代码,以了解您是否安全


我认为,当需要对数据进行排序时,最好进行完整的排序,使用“现在”这样的单一时间,这样,如果排序需要足够长的时间才能完成,就不会有跳过边界的风险。

我不知道比较器如何检测到更改,除非它还记得目前看到的最新价值观——这听起来像是一种注定以眼泪告终的方法

我建议你按照以下思路做一些事情:

  • 在无序的集合(或列表)中收集数据
  • 找到最新的值
  • 基于该值创建一个比较器,以便使用该比较器的所有比较都是固定的(即,它永远不会基于相同的输入值返回不同的结果;比较器本身是不可变的,尽管它取决于构造函数中最初提供的值)
  • 使用该比较器创建一个已排序的集合(以任何方式看起来都是最好的,这取决于您想用它做什么)
不,这行不通

如果在集合中使用可比较的键,则两个键之间的比较结果必须随时间保持不变


在二叉树中存储密钥时,路径中的每个分支都被选择作为比较操作的结果。如果以后的比较返回不同的结果,将使用不同的fork,并且将找不到以前存储的密钥。

出于以下几个原因,我建议不要这样做:

  • 由于它基本上是幕后的一棵红黑树(不必在每次插入时从头开始重新构建),因此很容易导致树的错误部分出现值(使大多数TreeSet API无效)
  • 该行为未在规范中定义,因此可能会在以后更改,即使它现在正在工作
  • 将来,当任何远程接触此代码的内容出现异常错误时,您将