/**
* This file is part of PaxmlCore.
*
* PaxmlCore is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PaxmlCore is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with PaxmlCore. If not, see <http://www.gnu.org/licenses/>.
*/
package org.paxml.util;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* The utils for traversing collections.
*
* @author Xuetao Niu
*
*/
public class TraversalUtils {
/**
* Make a list of maps out of a map of lists. The given map is treated as a
* grid, where the row index is the map key. The combination algorithm is to
* grab an item from each row of the grid to make a map, where each result
* map is contains that chosen item associated with the key. For instance,
* map: {a:[1,2],b:[3,4]} becomes list
* [{a:1,b:3},{a:1,b:4},{a:2,b:3},{a:2,b:4}].
*
* @param map
* the map of lists
* @return the list of maps
*/
public static <K, V> List<Map<K, V>> combination(Map<K, List<V>> map) {
List<K> keys = new ArrayList<K>(map.size());
List<List<V>> grid = new ArrayList<List<V>>(map.size());
for (Map.Entry entry : map.entrySet()) {
keys.add((K) entry.getKey());
List<V> row = (List<V>) entry.getValue();
if (row == null) {
row = new ArrayList<V>();
row.add(null);
}
grid.add(row);
}
return combine(keys.size() - 1, keys, grid);
}
private static <K, V> List<Map<K, V>> combine(int rowIndex, List<K> keys, List<List<V>> grid) {
List<V> row = grid.get(rowIndex);
K key = keys.get(rowIndex);
List<Map<K, V>> result = new ArrayList();
if (rowIndex <= 0) {
// reached the 1st row, create new maps
for (V val : row) {
Map<K, V> map = new LinkedHashMap();
map.put(key, val);
result.add(map);
}
} else {
// not to the 1st row yet
for (V val : row) {
List<Map<K, V>> created = combine(rowIndex - 1, keys, grid);
for (Map<K, V> map : created) {
map.put(key, val);
}
result.addAll(created);
}
}
return result;
}
}