3 回答
TA贡献1817条经验 获得超14个赞
将每个日期放入一个新集合中,按日期对其进行排序,然后创建包含集合中相邻日期的新对象。
尝试:
public static void main(String[] args) {
List<YourClass> list = new ArrayList<>();
list.add(new YourClass(new Date(100000000), new Date(200000000)));
list.add(new YourClass(new Date(150000000), new Date(250000000)));
list.add(new YourClass(new Date(50000000), new Date(300000000)));
System.out.println(list);
List<Date> dates = new ArrayList<>();
for (YourClass yc : list){
if (!dates.contains(yc.beginning)) dates.add(yc.beginning);
if (!dates.contains(yc.end)) dates.add(yc.end);
}
Collections.sort(dates);
List<YourClass> list2 = new ArrayList<>();
for (int i=0; i < dates.size() -1; i++){
list2.add(new YourClass(dates.get(i), dates.get(i+1)));
}
System.out.println(list2);
}
public static class YourClass {
Date beginning;
Date end;
public YourClass(Date beginning, Date end) {
this.beginning = beginning;
this.end = end;
}
@Override
public String toString() {
return "\n" + beginning + " -> " + end ;
}
}
TA贡献1852条经验 获得超1个赞
我想要做的是按日期对所有 DateTime 开始和所有 DateTime 结束进行排序。
你可以做一个或另一个,但不能同时做。
要按开始日期排序(在实践中似乎很明智),请实现compareTo方法。
return this.getDateRange().getStart().compareTo( thatStart );
要按停止日期排序(我认为这没有任何意义),请实现Comparator接口。
return
t1.getDateRange().getEnd().compareTo(
t2.getDateRange().getEnd()
)
;
LocalDate
正如其他人所指出的,您应该使用现代java.time类,而不是可怕的旧Date//类Calendar。SimpleDateFormat对于仅日期值,没有时间和时区,请使用LocalDate.
LocalDateRange
正如jbx 的答案所讨论的,您应该将您的学期的开始日期和结束日期表示为一对。但是当一个类已经存在时不要写一个类。使用ThreeTen-Extra项目中LocalDateRange的类。该项目为java.time类添加了功能。
Comparable
在您的Term类上,实现Comparable接口以启用简单轻松的排序。添加方法compareTo。显而易见的方法是比较LocalDate每个Term对象的LocalDateRange对象的开始。
该类LocalDate实现compareTo了,不,我们不必这样做。
@Override
public int compareTo ( Object o ) {
if ( this == o ) return 0;
if ( o == null || getClass() != o.getClass() ) return 0;
LocalDate thatStart = ( ( Term ) o ).getDateRange().getStart();
return this.getDateRange().getStart().compareTo( thatStart );
}
请参阅有关对象排序的 Java 教程。
按停止日期排序
您的问题不清楚,但您似乎要求按结束日期进行排序。我无法想象这在实际中是如何有用的。但无论如何,解决方案是通过提供Comparator接口的实现来进行排序。
@Override
public int compare ( Term t1 , Term t2 ) {
return t1.getDateRange().getEnd().compareTo( t2.getDateRange().getEnd() );
}
示例类
这是一个示例Term类。可能不是生产质量的代码,但应该让你朝着正确的方向前进。
package com.basilbourque.example;
import org.threeten.extra.LocalDateRange;
import java.time.LocalDate;
import java.time.Month;
import java.util.*;
public class Term implements Comparable {
private UUID id;
private LocalDateRange dateRange;
// Constructor
public Term ( LocalDate start , LocalDate stop , UUID id ) {
Objects.requireNonNull( start ); // TODO: Add more such checks for all arguments.
if ( start.getYear() < 2015 ) { // TODO: Add more such checks for too far into the past or future, for both start and for stop.
throw new IllegalArgumentException( "Year of start date is too far in the past. Message # afcd30a0-b639-4ccf-b064-18cc2ea8587b." );
}
this.id = id;
this.dateRange = LocalDateRange.of( start , stop );
}
// Alternative constructor.
public Term ( LocalDateRange dateRange , UUID id ) {
this( dateRange.getStart() , dateRange.getEnd() , id );
}
// --------| Object |-------------------------
@Override
public String toString ( ) {
return "Term{ " +
"id=" + id +
" | dateRange=" + dateRange +
" }";
}
public UUID getId ( ) {
return id;
}
public LocalDateRange getDateRange ( ) {
return dateRange;
}
@Override
public boolean equals ( Object o ) {
if ( this == o ) return true;
if ( o == null || getClass() != o.getClass() ) return false;
Term term = ( Term ) o;
return this.getId().equals( term.getId() );
}
@Override
public int hashCode ( ) {
return Objects.hash( this.getId() );
}
@Override
public int compareTo ( Object o ) {
if ( this == o ) return 0; // If same object.
if ( o == null || getClass() != o.getClass() ) return 0;
LocalDate thatStart = ( ( Term ) o ).getDateRange().getStart();
return this.getDateRange().getStart().compareTo( thatStart );
}
static public class StopDateComparator implements Comparator < Term > {
@Override
public int compare ( Term t1 , Term t2 ) {
return t1.getDateRange().getEnd().compareTo( t2.getDateRange().getEnd() );
}
}
}
试试看。
public static void main ( String[] args ) {
Term t1 = new Term( LocalDate.of( 2018 , Month.JUNE , 23 ) , LocalDate.of( 2018 , Month.JULY , 23 ) , UUID.randomUUID() );
Term t2 = new Term( LocalDate.of( 2018 , Month.JANUARY , 23 ) , LocalDate.of( 2018 , Month.DECEMBER , 23 ) , UUID.randomUUID() );
Term t3 = new Term( LocalDate.of( 2018 , Month.MARCH , 23 ) , LocalDate.of( 2018 , Month.APRIL , 23 ) , UUID.randomUUID() );
List < Term > terms = new ArrayList <>( List.of( t1 , t2 , t3 ) );
System.out.println( "Before natural sort: " + terms );
Collections.sort( terms );
System.out.println( "After natural sort: " + terms );
Collections.sort( terms , new Term.StopDateComparator() );
System.out.println( "After Comparator sort: " + terms );
}
自然排序前:[Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | 日期范围=2018-06-23/2018-07-23 },期限{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | 日期范围=2018-01-23/2018-12-23 },期限{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | 日期范围=2018-03-23/2018-04-23 }]
自然排序后:[Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | 日期范围=2018-01-23/2018-12-23 },期限{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | 日期范围=2018-03-23/2018-04-23 },期限{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | 日期范围=2018-06-23/2018-07-23 }]
比较器排序后:[Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | 日期范围=2018-03-23/2018-04-23 },期限{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | 日期范围=2018-06-23/2018-07-23 },期限{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | 日期范围=2018-01-23/2018-12-23 }]
abuts
如果您的Term对象应该连续运行,您可以使用该LocalDateRange::abuts方法进行测试。
比较的方法是半开放式,开始是包容性的,结束是排斥性的。因此,一年从一年的第一天开始,一直到但不包括下一年的第一天。您在问题的示例中展示了这一点。
TA贡献1966条经验 获得超4个赞
我认为这个问题不仅仅是关于排序,还有关于将重叠的间隔分成更小的部分。您必须经常使用Interval Arithmetic。
使用 Java 8,您可以首先将“术语”编码为时间间隔,它本身就是Comparable. 如果用户指定重叠的间隔,第二部分将把你的间隔分成多个。
class Interval implements Comparable<Interval> {
private final LocalDateTime start;
private final LocalDateTime end;
public Interval(LocalDateTime start, LocalDateTime end) {
this.start = start;
this.end = end;
}
public int compareTo(Interval that) {
return this.start.compareTo(that.start);
}
public boolean overlaps(Interval that) {
return !this.isBefore(that) && !this.isAfter(that);
}
public boolean contains(Interval that) {
return this.start.isBefore(that.start) && this.end.isAfter(that.end);
}
public boolean isBefore(Interval that) {
return this.end.isBefore(that.start);
}
public boolean isAfter(Interval that) {
return this.start.isAfter(that.end);
}
public Set<Interval> fragment(Interval that) {
if (that.start.isBefore(this.start)) {
return that.fragment(this);
}
Set<Interval> result = new HashSet<>();
if (this.end.isBefore(that.start)) {
result.add(this);
result.add(that);
result.add(new Interval(this.end, that.start));
} else if ((this.end.isAfter(that.start) && this.end.isBefore(that.end)) {
result.add(new Interval(this.start, that.start);
result.add(new Interval(that.start, this.end);
result.add(new Interval(this.end, that.end));
} else if (this.end.isAfter(that.end)) {
result.add(new Interval(this.start, that.start);
result.add(new Interval(that);
result.add(new Interval(that.end, this.end));
}
}
}
您现在可以对它们进行排序,因为Intervals 可以按开始日期进行比较。每当用户输入一个新的Interval(术语)时,您必须通过列表检查它是否contains()存在间隔,或者它是否在它之前,使用isBefore()或isAfter()。如果它overlaps()你必须小心是否还要检查它是否与列表中的下一个间隔重叠。
然后,您可以调用fragment()which 会将 2 个间隔组合成更小的间隔。您需要小心删除以前的。因此,只需浏览列表并检查它们是否重叠可能是有意义的。如果您到达终点,您仍然可以使用fragment()组合两个不相交的间隔。
添加回答
举报
