package org.archive.format.json; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.List; import java.util.Stack; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.lang.StringUtils; public class CrossProductOfLists<T> { private static final Logger LOG = Logger.getLogger(CrossProductOfLists.class.getName()); public List<List<T>> crossProduct(List<List<List<T>>> listOfLists) { if(LOG.isLoggable(Level.INFO)) { int count = listOfLists.size(); LOG.info(String.format("Total of (%d) lists to cross product",count)); for(int i = 0; i < count; i++) { LOG.info(String.format("Field (%d) is (%d) deep",i,listOfLists.get(i).size())); for(List<T> inner : listOfLists.get(i)) { LOG.info( String.format("----(%d):(%s)" ,i,StringUtils.join(inner.toArray(),",") ) ); } } } ArrayList<List<T>> results = new ArrayList<List<T>>(); Stack<T> current = new Stack<T>(); Deque<List<List<T>>> remainder = new ArrayDeque<List<List<T>>>(listOfLists); recurse(remainder,current,results); return results; } private void recurse(Deque<List<List<T>>> remainder, Stack<T> current, ArrayList<List<T>> accumulation) { if(remainder.isEmpty()) { // all done: // dump(new ArrayList<T>(current)); accumulation.add(new ArrayList<T>(current)); } else { List<List<T>> cur = remainder.removeFirst(); for(List<T> o : cur) { current.addAll(o); recurse(remainder,current,accumulation); for(int i = 0; i < o.size(); i++) { current.pop(); } } remainder.addFirst(cur); } } // private void dump(ArrayList<T> a) { // StringBuilder sb = new StringBuilder(); // boolean first = false; // for(T o : a) { // if(first) { // first = false; // } else { // sb.append(","); // } // sb.append(o.toString()); // } // //System.out.println("CrossOutput:" + sb.toString()); // } }