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類??赡懿皇巧a質量的代碼,但應該讓你朝著正確的方向前進。
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()組合兩個不相交的間隔。
添加回答
舉報