Monday, 15 August 2011

range - JAVA & Joda Time API: compare intervals, detect overlapping and generate new intervals -



range - JAVA & Joda Time API: compare intervals, detect overlapping and generate new intervals -

i working on project confuses me bad right now.

given list<timeinterval> list contains elements of class timeinterval, looks this:

public class timeinterval { private static final instant constant = new instant(0); private final localdate validfrom; private final localdate validto; public timeinterval(localdate validfrom, localdate validto) { this.validfrom = validfrom; this.validto = validto; } public boolean isvalid() { seek { homecoming tointerval() != null; } grab (illegalargumentexception e) { homecoming false; } } public boolean overlapswith(timeinterval timeinterval) { homecoming this.tointerval().overlaps(timeinterval.tointerval()); } private interval tointerval() throws illegalargumentexception { homecoming new interval(validfrom.todatetime(constant), validto.todatetime(constant)); }

the intervals generated using following:

timeinterval ti = new timeinterval(ld_datevalidfrom, ld_datevalidto);

the intervals within list may overlap:

|--------------------| |-------------------|

this should result in:

|-------||-----------||------|

it should not result in:

|--------|-----------|-------|

generally speaking in numbers:

i1: 2014-01-01 - 2014-01-30 i2: 2014-01-07 - 2014-01-15

that should result in:

i1: 2014-01-01 - 2014-01-06 i2: 2014-01-07 - 2014-01-15 i3: 2014-01-16 - 2014-01-30

i'm using joda time api since i'm using first time, don't have clue how solve problem. had @ method overlap() / overlapwith() still don't it.

your help much appreciated!

update found similar problem >here< doesn't help me now.

i tried on , on again, , though worked first intervals tested, doesn't work way wanted to.

here intervals have been given:

2014-10-20 ---> 2014-10-26 2014-10-27 ---> 2014-11-02 2014-11-03 ---> 2014-11-09 2014-11-10 ---> 2014-11-16 2014-11-17 ---> 9999-12-31

this function using generate new intervals:

private list<interval> cleanintervallist(list<interval> sourcelist) { treemap<datetime, integer> endpoints = new treemap<datetime, integer>(); // fill treemap timeinterval list. each start point, // increment value in map, , each end point, decrement it. (interval interval : sourcelist) { datetime start = interval.getstart(); if (endpoints.containskey(start)) { endpoints.put(start, endpoints.get(start)+1); } else { endpoints.put(start, 1); } datetime end = interval.getend(); if (endpoints.containskey(end)) { endpoints.put(end, endpoints.get(start)-1); } else { endpoints.put(end, 1); } } system.out.println(endpoints); int curr = 0; datetime currstart = null; // iterate on (sorted) map. note first iteration used // simply initialize curr , currstart meaningful values, no // interval precedes first point. list<interval> targetlist = new linkedlist<interval>(); (entry<datetime, integer> e : endpoints.entryset()) { if (curr > 0) { if (e.getkey().equals(endpoints.lastentry().getkey())){ targetlist.add(new interval(currstart, e.getkey())); } else { targetlist.add(new interval(currstart, e.getkey().minusdays(1))); } } curr += e.getvalue(); currstart = e.getkey(); } system.out.println(targetlist); homecoming targetlist; }

this output looks like:

2014-10-20 ---> 2014-10-25 2014-10-26 ---> 2014-10-26 2014-10-27 ---> 2014-11-01 2014-11-02 ---> 2014-11-02 2014-11-03 ---> 2014-11-08 2014-11-09 ---> 2014-11-09 2014-11-10 ---> 2014-11-15 2014-11-16 ---> 2014-11-16 2014-11-17 ---> 9999-12-31

and output should like:

2014-10-20 ---> 2014-10-26 2014-10-27 ---> 2014-11-02 2014-11-03 ---> 2014-11-09 2014-11-10 ---> 2014-11-16 2014-11-17 ---> 9999-12-31

since there no overlap in original intervals, don't why produces stuff like

2014-10-26 ---> 2014-10-26 2014-11-02 ---> 2014-11-02 2014-11-09 ---> 2014-11-09 etc

i've been trying prepare day long , i'm still not getting there :( more help much appreciated!

here suggested algorithm, based on reply have found. first, need sort end points of intervals.

treemap<localdate,integer> endpoints = new treemap<localdate,integer>();

this map's keys - sorted since treemap - localdate objects @ start , end of intervals. mapped number represents number of end points @ date subtracted number of start points @ date.

now traverse list of timeintervals. each one, start point, check whether in map. if so, add together 1 integer. if not, add together map value of 1.

for end point of same interval, if exists in map, subtract 1 integer. if not, create value of -1.

once finished filling endpoints, create new list "broken up" intervals create.

list<timeinterval> newlist = new arraylist<timeinterval>();

now start iterating on endpoints. if had @ to the lowest degree 1 interval in original list, you'll have @ to the lowest degree 2 points in endpoints. take first, , maintain key (localdate) in variable currstart, , associated integer in variable (curr or something).

loop starting sec element until end. @ each iteration:

if curr > 0, create new timeinterval starting @ currstart , ending @ current key date. add together newlist. add integer value curr. assign key next currstart.

and on until end.

what happens here this: ordering dates makes sure have no overlaps. each new interval guaranteed not overlap new 1 since have exclusive , sorted end points. trick here find spaces in timeline not covered intervals @ all. empty spaces characterized fact curr zero, means intervals started before current point in time have ended. other "spaces" between end points covered @ to the lowest degree 1 interval there should corresponding new interval in newlist.

here implementation, please notice did not utilize joda time (i don't have installed @ moment, , there no particular feature here requires it). created own rudimentary timeinterval class:

public class timeinterval { private final date validfrom; private final date validto; public timeinterval(date validfrom, date validto) { this.validfrom = validfrom; this.validto = validto; } public date getstart() { homecoming validfrom; } public date getend() { homecoming validto; } @override public string tostring() { homecoming "[" + validfrom + " - " + validto + "]"; } }

the of import thing add together accessor methods start , end able perform algorithm wrote it. in reality, should utilize joda's interval or implement readableinterval if want utilize extended features.

now method itself. work yours you'll have alter date localdate:

public static list<timeinterval> breakoverlappingintervals( list<timeinterval> sourcelist ) { treemap<date,integer> endpoints = new treemap<>(); // fill treemap timeinterval list. each start point, increment // value in map, , each end point, decrement it. ( timeinterval interval : sourcelist ) { date start = interval.getstart(); if ( endpoints.containskey(start)) { endpoints.put(start, endpoints.get(start) + 1); } else { endpoints.put(start, 1); } date end = interval.getend(); if ( endpoints.containskey(end)) { endpoints.put(end, endpoints.get(start) - 1); } else { endpoints.put(end, -1); } } int curr = 0; date currstart = null; // iterate on (sorted) map. note first iteration used // simply initialize curr , currstart meaningful values, no // interval precedes first point. list<timeinterval> targetlist = new arraylist<>(); ( map.entry<date,integer> e : endpoints.entryset() ) { if ( curr > 0 ) { targetlist.add(new timeinterval(currstart, e.getkey())); } curr += e.getvalue(); currstart = e.getkey(); } homecoming targetlist; }

(note more efficient utilize mutable integer-like object rather integer here, opted clarity).

java range jodatime overlap intersect

No comments:

Post a Comment