読者です 読者をやめる 読者になる 読者になる

利用期間重複の詳細リストを求める(1)

スケジュール管理などで、期間の重複を避けるための処理は良く書くことがあります。
要件として、既に重複が存在する状態の重複した期間の詳細を別に求めるという機会は、
少ないと思います。
それでも、重複した日の重複したもののリストを一覧で、日付毎に出したい。
なんて、要件が稀にあります。

例) Elementオブジェクトが、id と期間(Date型)を持ってます。

期間が重複するパターンで、
id=1、10月4日~10月7日
id=2、10月6日~10月10日

の場合、重複した日付毎に、
  10月6日 → id=1 のElementオブジェクトと id=2 のElementオブジェクト2個を持つ。
  10月7日 → id=1 のElementオブジェクトと id=2 のElementオブジェクト2個を持つ。
他の日付はデータ無し!!!

ということです。
Java7 で書いてみます。

public TreeMap<Date, List<Element>> createDuplicateMap(List<Element> list){
   TreeMap<Date, List<Element>> rtn = new TreeMap<Date, List<Element>>();
   final Map<Date, TreeSet<Element>> map = new HashMap<Date, TreeSet<Element>>();
   Collections.sort(list, new Comparator<Element>(){
      @Override
      public int compare(Element o1, Element o2){
         if (o1.start_date.compareTo(o2.end_date) <= 0 && o1.end_date.compareTo(o2.start_date) >= 0){
            Calendar cs = Calendar.getInstance();
            Calendar ce = Calendar.getInstance();
            cs.setTime(o1.start_date);
            ce.setTime(o1.end_date);

            while(cs.compareTo(ce) <= 0){
               Date d = cs.getTime();
               TreeSet<Element> l = map.containsKey(d) ? map.get(d) : new TreeSet<Element>(new Comparator<Element>(){
                  @Override
                  public int compare(Element e1, Element e2){
                     return e1.start_date.compareTo(e2.start_date);
                  }
               });
               l.add(o1);
               map.put(cs.getTime(), l);

               cs.add(Calendar.DAY_OF_MONTH, 1);
            }

            cs.setTime(o2.start_date);
            ce.setTime(o2.end_date);

            while(cs.compareTo(ce) <= 0){
               Date d = cs.getTime();
               TreeSet<Element> l = map.containsKey(d) ? map.get(d) : new TreeSet<Element>(new Comparator<Element>(){
                  @Override
                  public int compare(Element e1, Element e2){
                     return e1.start_date.compareTo(e2.start_date);
                  }
               });
               l.add(o2);
               map.put(cs.getTime(), l);
               cs.add(Calendar.DAY_OF_MONTH, 1);
            }

         }
         return o1.start_date.compareTo(o2.start_date);
      }}
   );

   for(Date d:map.keySet()){
      if (map.get(d).size() > 1){
         List<Element> elist = new ArrayList<Element>();
         for(Element e:map.get(d)){
            elist.add(e);
         }
         rtn.put(d, elist);
      }
   }

   return rtn;
}

Java8 で書いてみます。(少しだけ)

public TreeMap<Date, List<Element>> createDuplicateMap(List<Element> list){
   TreeMap<Date, List<Element>> rtn = new TreeMap<Date, List<Element>>();
   final Map<Date, TreeSet<Element>> map = new HashMap<Date, TreeSet<Element>>();
   list.sort((e1, e2)->{
      if (e1.start_date.compareTo(e2.end_date) <= 0 && e1.end_date.compareTo(e2.start_date) >= 0){
         Calendar cs = Calendar.getInstance();
         Calendar ce = Calendar.getInstance();
         cs.setTime(e1.start_date);
         ce.setTime(e1.end_date);
         while(cs.compareTo(ce) <= 0){
            Date d = cs.getTime();
            TreeSet<Element> l = map.containsKey(d) ? map.get(d) : new TreeSet<Element>((a, b)->a.start_date.compareTo(b.start_date));
            l.add(e1);
            map.put(cs.getTime(), l);
            cs.add(Calendar.DAY_OF_MONTH, 1);
         }
         cs.setTime(e2.start_date);
         ce.setTime(e2.end_date);
         while(cs.compareTo(ce) <= 0){
            Date d = cs.getTime();
            TreeSet<Element> l = map.containsKey(d) ? map.get(d) : new TreeSet<Element>((a, b)->a.start_date.compareTo(b.start_date));
            l.add(e2);
            map.put(cs.getTime(), l);
            cs.add(Calendar.DAY_OF_MONTH, 1);
         }
      }
      return e1.start_date.compareTo(e2.start_date);
   }
);
   map.forEach((d, v)->{
      if (v.size() > 1){
         rtn.put(d, Arrays.asList(v.toArray(new Element[]{})));
      }
   });

   return rtn;
}


15行程度しか減ってない。。。

もっと短くコンパクトに書きたいんだけど。。。