List の Diff

java.util.List のDiff の準備ができたのでいよいよDiff実行するものを作成した。

先日投稿した http://blog.zaq.ne.jp/oboe2uran/article/372/ 準備を踏まえて
Google collection Library の
com.google.common.collect.MapDifference
を利用する。

Diff実行クラスとしてコンストラクタで生成してから利用するメソッドとstatic メソッド
両方を用意することにした

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import com.google.common.collect.MapDifference;
import com.google.common.collect.Maps;
import com.google.common.collect.MapDifference.ValueDifference;

/**
 * use com.google.common.collect.MapDifference
 * List の Diff を実行して結果を List 1要素単位でDiff結果表現する ListDifference の
 * Collection を返す。
 */

public final class Listy<E>{
   private Map<ListyDiffType,Collection<?>> map;

   /**
    * コンストラクタ
    * @param left 左側 java.util.List
    * @param right 右側 java.util.List
    */

   public Listy(List<E> left,List<E> right){
      this.map = new HashMap<ListyDiffType,Collection<?>>();
      Set<ListDifference<E>> setDiff = new TreeSet<ListDifference<E>>();
      Set<ListDifference<E>> setCommon = new TreeSet<ListDifference<E>>();
      Set<ListDifference<E>> setLeft = new TreeSet<ListDifference<E>>();
      Set<ListDifference<E>> setRight = new TreeSet<ListDifference<E>>();
      Map<Long,E> lmap = new HashMap<Long,E>();
      Map<Long,E> rmap = new HashMap<Long,E>();
      long ix = 0;
      for(E e : left){
         lmap.put(new Long(ix),e);
         ix++;
      }
      ix = 0;
      for(E e : right){
         rmap.put(new Long(ix),e);
         ix++;
      }
      MapDifference<Long,E> mdiff = Maps.difference(lmap,rmap);
      Map<Long,ValueDifference<E>> vmap = mdiff.entriesDiffering();
      for(final Long lx : vmap.keySet()){
         ValueDifference<E> vdiff = vmap.get(lx);
         setDiff.add(new ListDifference<E>(lx,vdiff.leftValue(),vdiff.rightValue()));
      }
      Map<Long,E> vlmap = mdiff.entriesOnlyOnLeft();
      for(Long lx : vlmap.keySet()){
         setLeft.add(new ListDifference<E>(lx,vlmap.get(lx),null));
      }
      Map<Long,E> vrmap = mdiff.entriesOnlyOnRight();
      for(Long lx : vrmap.keySet()){
         setRight.add(new ListDifference<E>(lx,null,vrmap.get(lx)));
      }
      Map<Long,E> mapCommon = mdiff.entriesInCommon();
      for(final Long lx : mapCommon.keySet()){
         setCommon.add(new ListDifference<E>(lx,mapCommon.get(lx),mapCommon.get(lx)));
      }
      this.map.put(ListyDiffType.DIFFERING,setDiff);
      this.map.put(ListyDiffType.COMMON,setCommon);
      this.map.put(ListyDiffType.ONLY_LEFT,setLeft);
      this.map.put(ListyDiffType.ONLY_RIGHT,setRight);
   }

   enum ListyDiffType{
      DIFFERING,COMMON,ONLY_LEFT,ONLY_RIGHT
   }

   /**
    * List 差が発生した行の結果Collection
    * @return Collection<ListDifference<E>>
    */

   @SuppressWarnings("unchecked")
   public Collection<ListDifference<E>> differing(){
      return (Collection<ListDifference<E>>)this.map.get(ListyDiffType.DIFFERING);
   }


   /**
    * List 共通行の結果Collection
    * @return Collection<ListDifference<E>>
    */

   @SuppressWarnings("unchecked")
   public Collection<ListDifference<E>> getCommons(){
      return (Collection<ListDifference<E>>)this.map.get(ListyDiffType.COMMON);
   }


   /**
    * 左側Only List の結果Collection
    * @return Collection<ListDifference<E>>
    */

   @SuppressWarnings("unchecked")
   public Collection<ListDifference<E>> getOnlyLeft(){
      return (Collection<ListDifference<E>>)this.map.get(ListyDiffType.ONLY_LEFT);
   }


   /**
    * 右側Only List の結果Collection
    * @return Collection<ListDifference<E>>
    */
   @SuppressWarnings("unchecked")
   public Collection<ListDifference<E>> getOnlyRight(){
      return (Collection<ListDifference<E>>)this.map.get(ListyDiffType.ONLY_RIGHT);
   }


   /**
    * List 差分を求める
    * @param left 左側 java.util.List
    * @param right 右側 java.util.List
    * @return Collection<ListDifference<E>>
    */

   public static <E> Collection<ListDifference<E>> differing(List<E> left,List<E> right){
      Set<ListDifference<E>> setDiff = new TreeSet<ListDifference<E>>();
      Map<Long,E> lmap = new HashMap<Long,E>();
      Map<Long,E> rmap = new HashMap<Long,E>();
      long ix = 0;
      for(E e : left){
         lmap.put(new Long(ix),e);
         ix++;
      }
      ix = 0;
      for(E e : right){
         rmap.put(new Long(ix),e);
         ix++;
      }
      MapDifference<Long,E> mdiff = Maps.difference(lmap,rmap);
      Map<Long,ValueDifference<E>> vmap = mdiff.entriesDiffering();
      for(final Long lx : vmap.keySet()){
         ValueDifference<E> vdiff = vmap.get(lx);
         setDiff.add(new ListDifference<E>(lx,vdiff.leftValue(),vdiff.rightValue()));
      }
      return setDiff;
   }

   /**
    * List 共通行を求める
    * @param left 左側 java.util.List
    * @param right 右側 java.util.List
    * @return Collection<ListDifference<E>>
    */

   public static <E> Collection<ListDifference<E>> getCommons(List<E> left,List<E> right){
      Set<ListDifference<E>> setCommon = new TreeSet<ListDifference<E>>();
      Map<Long,E> lmap = new HashMap<Long,E>();
      Map<Long,E> rmap = new HashMap<Long,E>();
      long ix = 0;
      for(E e : left){
         lmap.put(new Long(ix),e);
         ix++;
      }
      ix = 0;
      for(E e : right){
         rmap.put(new Long(ix),e);
         ix++;
      }
      MapDifference<Long,E> mdiff = Maps.difference(lmap,rmap);
      Map<Long,E> vmap = mdiff.entriesInCommon();
      for(final Long lx : vmap.keySet()){
         setCommon.add(new ListDifference<E>(lx,vmap.get(lx),vmap.get(lx)));
      }
      return setCommon;
   }

   /**
    * List 左側だけに存在する行を求める
    * @param left 左側 java.util.List
    * @param right 右側 java.util.List
    * @return Collection<ListDifference<E>>
    */

   public static <E> Collection<ListDifference<E>> getOnlyLeft(List<E> left,List<E> right){
      Set<ListDifference<E>> setLeft = new TreeSet<ListDifference<E>>();
      Map<Long,E> lmap = new HashMap<Long,E>();
      Map<Long,E> rmap = new HashMap<Long,E>();
      long ix = 0;
      for(E e : left){
         lmap.put(new Long(ix),e);
         ix++;
      }
      ix = 0;
      for(E e : right){
         rmap.put(new Long(ix),e);
         ix++;
      }
      MapDifference<Long,E> mdiff = Maps.difference(lmap,rmap);
      Map<Long,E> vmap = mdiff.entriesOnlyOnLeft();
      for(final Long lx : vmap.keySet()){
         setLeft.add(new ListDifference<E>(lx,vmap.get(lx),null));
      }
      return setLeft;
   }

   /**
    * List 右側だけに存在する行を求める
    * @param left 左側 java.util.List
    * @param right 右側 java.util.List
    * @return Collection<ListDifference<E>>
    */

   public static <E> Collection<ListDifference<E>> getOnlyRight(List<E> left,List<E> right){
      Set<ListDifference<E>> setRight = new TreeSet<ListDifference<E>>();
      Map<Long,E> lmap = new HashMap<Long,E>();
      Map<Long,E> rmap = new HashMap<Long,E>();
      long ix = 0;
      for(E e : left){
         lmap.put(new Long(ix),e);
         ix++;
      }
      ix = 0;
      for(E e : right){
         rmap.put(new Long(ix),e);
         ix++;
      }
      MapDifference<Long,E> mdiff = Maps.difference(lmap,rmap);
      Map<Long,E> vmap = mdiff.entriesOnlyOnRight();
      for(final Long lx : vmap.keySet()){
         setRight.add(new ListDifference<E>(lx,null,vmap.get(lx)));
      }
      return setRight;
   }
}