java - Combinaciones de Map<Object, List<Object>>
hashmap combinations (2)
Aquí hay una solución recursiva:
public static void main(String[] args) {
// your data map
Map<GC, List<RR>> map;
// the map entry set as list, which will help
// combining the elements
//
// note this is a modifiable list
List<Map.Entry<GC, List<RR>>> mapEntryList =
new ArrayList<Map.Entry<GC, List<RR>>>(map.entrySet());
// the combinations list, which will store
// the desired results
List<RR> combinations = new ArrayList<RR>();
doRecursion(mapEntryList, combinations);
}
private static void doRecursion(
List<Map.Entry<GC, List<RR>>> mapEntryList,
List<RR> combinations) {
// end of recursion
if (mapEntryList.isEmpty()) {
// do what you wish
//
// here i print each element of the combination
for (RR rr : combinations) {
System.out.println(rr);
}
System.out.println();
return;
}
// remove one GC from the entry list,
// then for each RR from the taken GC
// put RR in the combinations list,
// call recursion
// the remove RR from the combinations list
// end for each
// then put GC back into its list
Map.Entry<GC, List<RR>> entry = mapEntryList.remove(0);
List<RR> entryValue = new ArrayList<RR>(entry.getValue());
while (!entryValue.isEmpty()) {
RR rr = entryValue.remove(0);
combinations.add(rr);
doRecursion(mapEntryList, combinations);
combinations.remove(combinations.size() - 1);
}
mapEntryList.add(0, entry);
}
Tengo un HashMap<GC, List<RR>>
con datos de muestra como:
key values
gc1 - rr1
- rr2
- rr3
gc2 - rr4
- rr5
gc3 - rr6
Y necesito crear todas las combinaciones posibles de RR de diferentes GC como:
Combination1: rr1, rr4, rr6
Combination2: rr1, rr5, rr6
Combination3: rr2, rr4, rr6
Combination4: rr2, rr5, rr6
Combination5: rr3, rr4, rr6
Combination6: rr3, rr5, rr6
Lo que he intentado hasta ahora es, como sugiere @Sanket Makani, convertir mi HashMap<GC, List<RR>>
en una List<List<RR>>
, y luego recorrer todos los elementos como:
List<List<RR>> inputList = new ArrayList<List<RR>>();
for (Map.Entry<GC, List<RR>> rrList : Map.entrySet()) {
inputList.add(rrList.getValue());
}
List<List<RR>> combinationsList = new ArrayList<List<RR>>();
for (List<RR> rrList : inputList) {
List<RR> rrList1 = new ArrayList<RR>();
for (RR rr : rrList) {
rrList1.add(rr);
}
combinationsList.add(rrList1);
}
Esto no funciona para mí, ya que agrupa todo el RR dentro de un GC como:
Combination1: rr1, rr2, rr3
Combination2: rr4, rr5
Combination3: rr6
Entonces mi pregunta es, ¿cómo puedo adaptar mi código para obtener el resultado esperado?
PD: estoy trabajando con Java6 por desgracia, por lo que no se permiten lambdas / streams.
PS2: he visto preguntas similares, pero no puedo encontrar un ejemplo exacto de lo que estoy buscando.
EDITAR:
Esta es mi implementación final con la respuesta de @nandsito:
//this method groups RRs by GC key with a given list
HashMap<GC, List<RR>> GCRRHashMap = groupRRsByGC(list);
List<Map.Entry<GC, List<RR>>> mapEntryList = new ArrayList<Map.Entry<GC, List<RR>>>(GCRRHashMap.entrySet());
List<List<RR>> combinationsList = new ArrayList<List<RR>>();
List<RR> combinations = new ArrayList<RR>();
generateCombinations(mapEntryList, combinations, combinationsList);
private void generateCombinations(
List<Map.Entry<GC, List<RR>>> mapEntryList,
List<RR> combinations, List<List<RR>> combinationsList) {
if (mapEntryList.isEmpty()) {
combinationsList.add(new ArrayList<RoomStay>(combinations));
return;
}
Map.Entry<GC, List<RR>> entry = mapEntryList.remove(0);
List<RR> entryValue = new ArrayList<RR>(entry.getValue());
while (!entryValue.isEmpty()) {
RR rr = entryValue.remove(0);
combinations.add(rr);
generateCombinations(mapEntryList, combinations, combinationsList);
combinations.remove(combinations.size() - 1);
}
mapEntryList.add(0, entry);
}
Todo lo que realmente necesita hacer es trabajar a través de una lista de índice creciente:
0,0,0
0,1,0
1,0,0
1,1,0
2,0,0
... etc.
Debería ser obvio cómo traducir cada una de esas filas en valores de su estructura de datos. por ejemplo, 0,0,0
mapas para rr1, rr4, rr6
. Esto implicará convertir el mapa en una lista para que los índices sean consistentes.
Es muy parecido a un recuento de base-b normal donde se incrementa la columna más a la derecha y si se desborda, se pone a cero e incrementa la siguiente. La única diferencia es que cada columna se desborda en un número diferente.
Asi que:
boolean increment(int[] indexes) {
int column = 0;
while(true) {
indexes[column]++;
if(indexes[column] < numberOfRRsInColumn(column)) {
return true; // finished
}
indexes[column]=0;
column++;
if(column = indexes.length) {
return false; // can''t increment, no more.
}
}
}
Esta implementación usa indexes[0]
como la columna "más a la derecha". He pasado por alto numberOfRRsInColumn()
, pero debería ser bastante obvio cómo hacerlo.
Entonces:
int[] indexes = new int[mapsize];
do {
output(translate(map, indexes));
} while (increment(indexes));