001 /* 002 * $Id: CartesianProduct.java 3297 2010-08-26 19:09:03Z kredel $ 003 */ 004 005 package edu.jas.util; 006 007 008 import java.util.ArrayList; 009 import java.util.Iterator; 010 import java.util.List; 011 import java.util.NoSuchElementException; 012 013 014 /** 015 * Cartesian product with iterator. 016 * @author Heinz Kredel 017 */ 018 public class CartesianProduct<E> implements Iterable<List<E>> { 019 020 021 /** 022 * data structure. 023 */ 024 public final List<Iterable<E>> comps; 025 026 027 /** 028 * CartesianProduct constructor. 029 * @param comps components of the cartesian product. 030 */ 031 public CartesianProduct(List<Iterable<E>> comps) { 032 if (comps == null) { 033 throw new IllegalArgumentException("null components not allowed"); 034 } 035 this.comps = comps; 036 } 037 038 039 // /** 040 // * CartesianProduct constructor. 041 // * @param comps components of the cartesian product. 042 // */ 043 // public CartesianProduct(List<List<E>> comps) { 044 // this( listToIterable(comps) ); 045 // } 046 047 048 /** 049 * Get an iterator over subsets. 050 * @return an iterator. 051 */ 052 public Iterator<List<E>> iterator() { 053 return new CartesianProductIterator<E>(comps); 054 } 055 056 057 /** 058 * Transform list to iterables. 059 * @param comp components of the cartesian product. 060 * @return iterables taken fom lists. 061 */ 062 static <E> List<Iterable<E>> listToIterable(List<List<E>> comp) { 063 List<Iterable<E>> iter = new ArrayList<Iterable<E>>( comp.size() ); 064 for ( List<E> list : comp ) { 065 iter.add( list ); 066 } 067 return iter; 068 } 069 070 071 } 072 073 074 /** 075 * Cartesian product iterator. 076 * @author Heinz Kredel 077 */ 078 class CartesianProductIterator<E> implements Iterator<List<E>> { 079 080 081 /** 082 * data structure. 083 */ 084 final List<Iterable<E>> comps; 085 086 087 final List<Iterator<E>> compit; 088 089 090 List<E> current; 091 092 093 boolean empty; 094 095 096 /** 097 * CartesianProduct iterator constructor. 098 * @param comps components of the cartesian product. 099 */ 100 public CartesianProductIterator(List<Iterable<E>> comps) { 101 if (comps == null) { 102 throw new IllegalArgumentException("null comps not allowed"); 103 } 104 this.comps = comps; 105 current = new ArrayList<E>(comps.size()); 106 compit = new ArrayList<Iterator<E>>(comps.size()); 107 empty = false; 108 for (Iterable<E> ci : comps) { 109 Iterator<E> it = ci.iterator(); 110 if (!it.hasNext()) { 111 empty = true; 112 current.clear(); 113 break; 114 } 115 current.add(it.next()); 116 compit.add(it); 117 } 118 //System.out.println("current = " + current); 119 } 120 121 122 /** 123 * Test for availability of a next tuple. 124 * @return true if the iteration has more tuples, else false. 125 */ 126 public synchronized boolean hasNext() { 127 return !empty; 128 } 129 130 131 /** 132 * Get next tuple. 133 * @return next tuple. 134 */ 135 public synchronized List<E> next() { 136 if (empty) { 137 throw new NoSuchElementException("invalid call of next()"); 138 } 139 List<E> res = new ArrayList<E>(current); 140 // search iterator which hasNext 141 int i = compit.size() - 1; 142 for (; i >= 0; i--) { 143 Iterator<E> iter = compit.get(i); 144 if (iter.hasNext()) { 145 break; 146 } 147 } 148 if (i < 0) { 149 empty = true; 150 return res; 151 } 152 // update iterators 153 for (int j = i + 1; j < compit.size(); j++) { 154 Iterator<E> iter = comps.get(j).iterator(); 155 compit.set(j, iter); 156 } 157 // update current 158 for (int j = i; j < compit.size(); j++) { 159 Iterator<E> iter = compit.get(j); 160 E el = iter.next(); 161 current.set(j, el); 162 } 163 return res; 164 } 165 166 167 /** 168 * Remove a tuple if allowed. 169 */ 170 public void remove() { 171 throw new UnsupportedOperationException("cannnot remove tuples"); 172 } 173 174 }