java - Grouping objects based on overlapping time interval -


i have class,

class a{     ...     private interval interval;     ... }  //maintaining epoch time class interval{     private long left;     private long right;      public interval(long left, long right){         this.left = left;         this.right = right;     } //getters , setters } 

i have list of objects list<a> , want group objects have overlapping(transitive overlapping, i.e. a = b, b = c = c) intervals. lets suppose have 4 objects,

a1 - interval - 09:00 10:00 a2 - interval - 13:00 14:00 a3 - interval - 10:10 12:00 a4 - interval - 09:30 10:30 

the result of program should give me 2 lists,

list1 - a1,a3,a4 list2 - a2 

any suggestions on solving issue and/or pseudo-code?

sorry verbosity, believe question merits :-) . solution n*log(n) in number of intervals. location complexity occurs within sorting of intervals. note solution takes care include cases 1 interval contained inside another. result groups have sub-intervals reverse ordered, can fix if reversing list @ end. wouldn't recommend fixing inserting joined intervals @ beginning rather end increases complexity o(n^2) if using arraylist based implementation. suppose use linkedlist , insert @ beginning, might hurt in other places, depending on these groups after you've formed them.

public static long max(long a, long b){     return (a>b ? : b); }  public static long min(long a, long b){     return (a<b ? : b); }  /**  * meta interval composed of sub intervals. left endpoint  * leftmost point of subintervals , right endpoint   * rightmost point of subintervals.   */ static class metainterval extends interval{      /**      * meta intervals composed of lists of subintervals.      */     private list<interval> subintervals;      public metainterval(interval initialsubinterval){         super(initialsubinterval.getleft(),initialsubinterval.getright(),null);         this.subintervals = new arraylist<interval>();         this.subintervals.add(initialsubinterval);     }      public void join(metainterval other){         verifyoverlap(other);          this.setleft(min(this.getleft(),other.getleft()));         this.setright(max(this.getright(),other.getright()));         this.subintervals.addall(other.getsubintervals());          other.invalidate();     }      public void setsubintervals(list<interval> subintervals){         this.subintervals = subintervals;     }      public list<interval> getsubintervals(){         return this.subintervals;     }      private void invalidate(){         this.setsubintervals(null);         this.setleft(0);         this.setright(0);     }      public boolean isinvalid(){         return this.getsubintervals()==null;     }   }  //maintaining epoch time static class interval implements comparable<interval>{     private long left;     private long right;      private string intervalid;      public interval(long left, long right, string intervalid){         this.left = left;         this.right = right;         this.intervalid = intervalid;     }      public boolean pointisin(long point){         return (point>=this.getleft() && point<=this.getright());     }      public long getleft(){         return left;     }      public long getright(){         return right;     }      public void setleft(long left){         this.left = left;     }      public void setright(long right){         this.right = right;     }      public string getintervalid(){         return intervalid;     }      public boolean overlaps(interval other){         return pointisin(other.getleft()) || pointisin(other.getright()) || other.pointisin(getleft()) || other.pointisin(getright());     }      public void verifyoverlap(interval other){         if(!overlaps(other)){             throw new illegalstateexception("other interval not overlap");         }     }      /**      * sort leftmost part of interval.      */     @override     public int compareto(interval o) {         return long.compare(this.getleft(), o.getleft());     }      public string tostring(){         return intervalid+":["+getleft()+","+getright()+"]";     } }  /**  * given list of intervals, returns list of interval groups  * intervals in groups overlap. if overlaps b ,  * b c, a,b,and c returned in group. supposing intervals  * d  , e share nothing a, b, or c, share each other, d , e  * returned separate group a,b,c.  * @param baseintervals  * @return  */ public static list<list<interval>> getoverlappinggroups(list<interval> baseintervals){     list<metainterval> basemetaintervals = tometaintervals(baseintervals);      list<metainterval> mergedmetaintervals = getmergedmetaintervals(basemetaintervals);      list<list<interval>> intervalgroups = metaintervalstogroups(mergedmetaintervals);     return intervalgroups; }    private static list<metainterval> getmergedmetaintervals(         list<metainterval> metaintervals) {     if(metaintervals.isempty()){         return metaintervals;     }     //order meta intervals starting point.     collections.sort(metaintervals);      //go through , merge overlapping meta intervals.     //this relies on logic if interval overlaps     //an interval started before it, once intervals     //before have been merged, interval have starting point     //consecutive starting point of the preceeding interval.     for(int i=0; i< metaintervals.size()-1; i++){         metainterval thisinterval = metaintervals.get(i);         metainterval nextinterval = metaintervals.get(i+1);          if(thisinterval.overlaps(nextinterval)){             nextinterval.join(thisinterval);         }     }      list<metainterval> resultintervals = new arraylist<metainterval>();      //all intervals original list either:     //(a) didn't overlap others     //(b) overlapped others , chosen represent merged group or     //(c) overlapped others, represented in group in meta      // interval, , marked invalid.     //go through , add valid intervals returned.      for(metainterval : metaintervals){         if(!i.isinvalid()){             resultintervals.add(i);         }     }     return resultintervals; }  /**  * convert list of meta intervals groups of intervals.  * @param mergedmetaintervals  * @return  */ private static list<list<interval>> metaintervalstogroups(         list<metainterval> mergedmetaintervals) {     list<list<interval>> groups = new arraylist<>(mergedmetaintervals.size());     for(metainterval metainterval : mergedmetaintervals){         groups.add(metainterval.getsubintervals());     }     return groups; }  private static list<metainterval> tometaintervals(         list<interval> baseintervals) {     arraylist<metainterval> metaintervals = new arraylist<metainterval>(baseintervals.size());     for(interval : baseintervals){         metaintervals.add(new metainterval(i));     }      return metaintervals; }  public static void main(string[] args){     interval = new interval(20, 30, "a");     interval b = new interval(21,22,"b");     interval c = new interval(500,503,"c");     interval d = new interval(28,38, "d");     interval e = new interval(490,502,"e");        //note: a,b, , d overlapping group, ,     //d , e another.     list<list<interval>> intervalgroups = getoverlappinggroups(arrays.aslist(a,b,c,d,e));      for(list<interval> group : intervalgroups){         system.out.println(group.tostring());     } } 

output:

[d:[28,38], b:[21,22], a:[20,30]] [c:[500,503], e:[490,502]] 

Comments

Popular posts from this blog

c# - Binding a comma separated list to a List<int> in asp.net web api -

Delphi 7 and decode UTF-8 base64 -

html - Is there any way to exclude a single element from the style? (Bootstrap) -