如何在列表中找到最大和最小日期?

10
我有一个对象集合,如下:Collection basics = periodic.getGeneratedBasic(); 当我遍历此集合并获取每个对象并将其强制转换时,我可以提取每个对象的日期。现在,在这一点上,我想检查此对象集合中哪个对象具有最早和最晚的日期。 有人知道如何做吗?
Date max;
Date min;
for(Object o:basics){
      Basic b = (Basic) o;
      Date temp;
      if(b.State=='U'){
           basicAList.add(ba);
           dateCollection.add(b.firstDateTime);
           temp= ;
           if(b.firstDateTime <)
     }
  }

@itro,请接受解决您问题的答案。 - Reddy
7个回答

21

在Java 8中,您可以这样做:

final Date maxDate = dates.stream()
    .max(Date::compareTo)
    .get();

13

这是一个经典的最小值和最大值问题。无论您的对象是日期、字符串或数字,重要的是它们是可比较的。

先排序再取最大/最小值

最直接的方法就像其他答案中提到的一样,使用Java内置的排序方法对集合进行排序。然后将第一个和最后一个元素作为您的最小/最大对象。不过这会将一个线性时间复杂度O(n)问题变成O(nlgn)。如果性能并不重要,您可以跳过阅读我的其余文本。我将为@Quoi的答案点赞。

线性时间复杂度的简单方法:

保持两个变量min和max,然后遍历您的集合中的每个元素。与当前的min和max进行比较,并获取正确的值,直到结束。

线性时间复杂度的优化方式

上面的方法很容易,但它带来了更多的比较(2n)。我们可以稍微优化一下。同样是min和max两个变量,在循环中,您需要取一对元素而不是单个元素。首先比较一对元素,将较大的元素与您的max变量进行比较,将较小的元素与您的min变量进行比较。现在我们只需要做3(n/2)次比较。

希望这能有所帮助。

编辑

我认为编写代码并不难。正如Quoi建议的那样,如果代码可以让答案更完整,我会添加它们。

请注意,在示例中,我使用了一个int数组。基本上它和Date对象是相同的。这些代码都写在一个单元测试方法中。看起来很长,因为我试图清晰地解释上面的思路。

@Test
    public void testx() {
        final int size = 300000;
        final int[] array = new int[size];
        final Random random = new Random();
        // fill a huge array for testing
        for (int i = 0; i < array.length; i++) {
            array[i] = random.nextInt();
        }

        int min1 = array[0], max1 = array[1], cmp1 = 0;
        int min2 = array[0], max2 = array[1], cmp2 = 0;

        for (int i = 2; i < array.length; i++) {
            min1 = array[i] < min1 ? array[i] : min1;
            cmp1++;
            max1 = array[i] > max1 ? array[i] : max1;
            cmp1++;
        }

        LOG.debug("linear time to find Max & Min simultaneously");
        LOG.debug("Size: {}", size);
        LOG.debug("Max : {}", max1);
        LOG.debug("Min : {}", min1);
        LOG.debug("Total comparisons : {}", cmp1);

        // optimized linear
        int bigger, smaller;
        final boolean odd = array.length % 2 == 1;
        final int till = odd ? array.length - 1 : array.length;
        for (int i = 2; i < till; i += 2) {

            if (array[i] >= array[i + 1]) {
                bigger = array[i];
                smaller = array[i + 1];
            } else {
                bigger = array[i + 1];
                smaller = array[i];
            }
            cmp2++;
            min2 = smaller < min2 ? smaller : min2;
            cmp2++;
            max2 = bigger > max2 ? bigger : max2;
            cmp2++;
        }
        if (odd) {
            min2 = array[size - 1] < min2 ? array[size - 1] : min2;
            max2 = array[size - 1] > max2 ? array[size - 1] : max2;
        }
        LOG.debug("====================================================");
        LOG.debug("optimized linear time to find Max & Min simultaneously");
        LOG.debug("Size: {}", size);
        LOG.debug("Max : {}", max2);
        LOG.debug("Min : {}", min2);
        LOG.debug("Total comparisons : {}", cmp2);
    }

输出

DEBUG:  linear time to find Max & Min simultaneously
DEBUG:  Size: 300000
DEBUG:  Max : 2147475519
DEBUG:  Min : -2147446732
DEBUG:  Total comparisons : 599996
DEBUG:  ====================================================
DEBUG:  optimized linear time to find Max & Min simultaneously
DEBUG:  Size: 300000
DEBUG:  Max : 2147475519
DEBUG:  Min : -2147446732
DEBUG:  Total comparisons : 449997

+1 好的解决方案。请添加代码片段以使答案完整。 - Subhrajyoti Majumder
完美的解释。 - sedran

12
为什么不使用 Collections.sort() 然后取第一个/最后一个条目?您可以使用 自然排序,或指定自己的 Comparator
请注意,这将在原地对集合进行排序。它不会给你一个新的已排序集合。

3
我已经按照您的想法实现了,但是使用了SortedSet的自动排序功能,代码如下:SortedSet<Date> set = new TreeSet<Date>();。在运行set.add( b.firstDateTime );时,它已经被排序过了,因此我可以调用Date min = set.first()Date max = set.last() - ViniciusPires
Sort-on-add通常比整个列表排序更快,并且使用“Set”可以防止重复条目... - ViniciusPires
抱歉,我的意思是 set.add( object.getDate() ) - ViniciusPires

7

DateComparable 接口的实现类,因此你可以使用 compareTo() 方法来比较两个 Date 对象:

dateOne.compareTo(dateTwo);
返回值:如果参数Date等于此Date,则返回值为0;如果此Date在Date参数之前,则返回小于0的值;如果此Date在Date参数之后,则返回大于0的值。
你也可以使用Collections.sort()(O(n logn))对整个Collection进行排序。
Collections.sort(dateCollection);

你可以使用Collections.max()来获取最大值,也可以使用Collections.min()来获取最小值(两者时间复杂度都为O(n))。


3
Date max = new Date(0);
Date min = new Date(0);
for(Object o:basics){
    Basic b = (Basic) o;
    if(b.State=='U'){
        basicAList.add(ba);
        dateCollection.add(b.firstDateTime);
        if(min.compareTo(b.firstDateTime) > 0) min = b.firstDateTime;
        else if(max.compareTo(b.firstDateTime) < 0) max = b.firstDateTime;
    }
}

temp= ; 不是有效的语法。 - Baz
@Baz,删掉那个变量...它不需要。 - Reddy

1
您可以按日期对收藏进行排序并获取它。如果按升序排序,则首先会得到最小的日期,最后是最大的日期;如果按降序排序,则会在顶部获得最大的日期,最后是最小的日期。

你会建议更好的方法吗? - Subhrajyoti Majumder

1

您可以查看this之前的SO帖子。您可以按日期对对象进行排序,然后选择集合中的第一个和最后一个项目。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接