【问题标题】:Why doesn't the set remove duplicates from the sorted list?为什么集合不从排序列表中删除重复项?
【发布时间】:2013-01-24 02:55:51
【问题描述】:

为什么集合不从排序列表中删除重复项?我已按第一行显示的升序对日期进行了排序,但该集合并未删除重复项。这是为什么 ? 程序打印:
[2009 年 4 月 20 日星期一 12:27:47 CDT 2009 年 4 月 20 日星期一 12:27:47 CDT 2009 年 12 月 20 日星期日 12:27:47 CST 2009] [2009 年 12 月 20 日星期日 12:27:47 CST,2009 年 4 月 20 日星期一 12:27:47 CDT 2009 年 4 月 20 日星期一 12:27:47 CDT]

不应该创建一个集合从集合中删除重复的日期吗?

    def void testLoadDoc()
     {
     Date date1 = getCurrentDate(3,20,2009)
     Date date2 = getCurrentDate(11,20,2009)
     Date date3 = getCurrentDate(3,20,2009)


     List<Date> dates = new ArrayList<Date>();
     dates.add(date2);
     dates.add(date1);
     dates.add(date3);

     Collections.sort(dates, new CurrencyDateComparator());
     Set uniqueDates = new HashSet(dates)

     println dates
     println uniqueDates

 }


 private Date getCurrentDate(int month, int day, int year)
 {

     Calendar cal = Calendar.getInstance();
     cal.set(YEAR, year);
     cal.set(MONTH, month);
     cal.set(DAY_OF_MONTH, day);
     return cal.getTime();

 }
}

class CurrencyDateComparator implements Comparator
{
    /* (non-Javadoc)
     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
     */
    public int compare(Object arg0, Object arg1)
    {
        Date p = (Date) arg0;
        Date q = (Date) arg1;

        if (p.before(q))
        {
            return -1;
        }
        else if (p.after(q))
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }

    public boolean equals(Object o)
    {
        if (o instanceof CurrencyDateComparator)
        {
            CurrencyDateComparator c = (CurrencyDateComparator) o;

            return this.equals(o);
        }
        else
        {
            return false;
        }
    }

【问题讨论】:

  • 为什么你在你的Comparator 中覆盖了equals
  • 您可以删除 equals() 方法,因为它永远不会返回 true,它将返回 false 或 Stack Overflow。

标签: java groovy


【解决方案1】:

您的所有日期都有不同的毫秒值,这些值不会打印在您的跟踪中。将毫秒设置为 0。

【讨论】:

  • @PeterLawrey:OP 正在使用 HashSet。他不能忽略毫秒。
  • 好点。我跳过了一步。将 TreeSet 与自定义比较器一起使用,它将对它们进行排序并删除重复项。
【解决方案2】:

首先

java.util.Date 带有时间信息,you need to zero out the time information 然后设置您要设置的内容或从自定义Comparator 中的比较中排除时间部分。

第二

您的自定义 Comparator 有问题且多余。 java.util.Date 已经实现了 Comparable,因此您无需再次比较日期,只需在第一个 Date 实例上调用 .compare(),并将第二个实例作为参数。

第三

还请记住,MONTHS 在 Caledar 中是零。一月 == 0 不是 1

第四

永远不要依赖java.util.Date 上的默认toString(),始终使用SimpleDateFormatter 实例,它将整个时间戳显示到毫秒,包括TimeZone (yyyy-MM-dd'T'HH:mm:ssZ),最好是ISO-8601 和@ 987654337@TimeZone 用于确定性行为。

【讨论】:

    【解决方案3】:

    当您使用Calendar.getInstance() 时,它会将“现在”返回到毫秒精度。更改 Y-M-D 字段并不会清除其中的任何内容,因此您的两个日期可能相差一毫秒或二十,这不包含在您看到输出的默认 toString() 实现中。

    如果您想将日历设置为特定时间,最简单的方法是先clear(),然后再开始设置字段。

    【讨论】:

      【解决方案4】:

      当您调用Calendar.getInstance() 时,您会得到一个使用当前时间初始化的Calendar。这包括小时、分钟、秒和毫秒。致电clearTime() 将其归零。

      【讨论】:

        【解决方案5】:

        您可以改用这个集合

        Set<Date> dates = new TreeSet<Date>(CurrencyDateComparator.INSTANCE);
        dates.add(date2);
        dates.add(date1);
        dates.add(date3);
        
        enum CurrencyDateComparator implements Comparator<Date> {
            INSTANCE;
        
            static final long MILLI_PER_DAY = 86400000L;
            public int compare(Date d1, Date d2) {
                // older versions of Java can use Double.compare()
                return Long.compare(d1.getTime() / MILLIS_PER_DAY, d2.getTime() / MILLIS_PER_DAY);
            }
        }
        

        【讨论】:

        • 即使在 UTC 时区,如果两个日期在同一天,它们也不会相等。有些日子有超过 24 小时。有些人少。
        • 我很确定如果没有夏令时,Java 中的每一天都一样长。他可以看到夏令时的问题,但他必须非常不走运。从技术上讲,Java 仅支持 GMT,而不支持 UTC 闰秒。
        • 夏令时只是问题的一部分。如果时区不是 UTC,那将不起作用。
        • 他真的应该使用 Joda Time 的 LocalDate。
        猜你喜欢
        • 2015-11-24
        • 2021-02-25
        • 2013-01-17
        • 1970-01-01
        • 2021-12-31
        • 2013-05-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多