2015-05-01 26 views
6

Esiste un modo efficace per trovare tutte le combinazioni possibili tra più enumerazioni in Java?Trova tutte le possibili combinazioni di enumerazioni

considerare i seguenti tre enumerazioni -

public enum EnumOne { 
    One ("One"), 
    OneMore ("OneMore"); 
} 

public enum EnumTwo { 
    Two ("Two"), 
} 

public enum EnumThree { 
    Three ("Three"), 
    ThreeMore ("ThreeMore"); 
} 

Vorrei l'uscita per la produzione di tutte le possibili combinazioni tra queste molteplici enumerazioni cioè

{EnumOne.One, EnumTwo.Two, EnumThree.Three}, 
{EnumOne.One, EnumTwo.Two, EnumThree.ThreeMore}, 
{EnumOne.OneMore, EnumTwo.Two, EnumThree.Three}, 
{EnumOne.OneMore, EnumTwo.Two, EnumThree.ThreeMore} 

nella speranza di trovare un modo efficace di gestirlo.

Grazie

+0

Definire "efficiente" – David

+0

Siete alla ricerca di qualcosa di meglio di nidificato loop? Non è chiaro cosa stai chiedendo – Misha

+0

Come meno ricorsivo possibile – JUG

risposta

-1

Come su qualcosa di simile.

void printAll(List<Class> enums, int i, String[] msg) { 
    if (!enums.get(i).isEnum()) { 
     throw new IllegalStateException(); 
    } 
    Object[] enumsConstants = enums.get(i).getEnumConstants(); 
    if (i == 0) { 
     //first iteration 
     for (Object o : enumsConstants) { 
      if (enums.size() == 1) { 
       System.out.println("{ " + o.toString() + " }"); 
      } else { 
       msg = new String[enums.size()]; 
       msg[0] = "{ " + o.toString(); 
       printAll(enums, i + 1, msg); 
      } 
     } 
    } else if (i == enums.size() - 1) { 
     //on the last iteration 
     for (Object o : enumsConstants) { 
      msg[i] = ", " + o.toString() + " }"; 
      System.out.println(Arrays.toString(msg)); 
     } 
    } else { 
     //middle iteration 
     for (Object o : enumsConstants) { 
      msg[i] = ", " + o.toString(); 
      printAll(enums, i + 1, msg); 
     } 
    } 
} 

Si potrebbe usare in questo modo

printAll(allMyEnumClassesList, 0, null); 
+0

Questo inserisce i valori in una stringa. Non sono così sicuro che sia ciò che viene richiesto. – dhke

+0

@dhke questo è lasciato all'interpretazione. In entrambi i casi l'output può essere modificato se necessario. Non è necessario essere una stringa [], può essere Object []. E non ha bisogno di essere stampato quando diventa un combo (può essere memorizzato da qualche parte se necessario). –

0

la complessità degli algoritmi è O (NxMxK ​​.... xZ) se mi sbaglio, non so se un "modo efficace" .... io uso come una soluzione backtracking

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 

public class ProductEnums { 

    public enum EnumOne { 
     One, 
     OneMore; 
    } 

    public enum EnumTwo { 
     Two, 
    } 

    public enum EnumThree { 
     Three, 
     ThreeMore; 
    } 

    public static void main(String[] args) { 
     // pass each values in enums 
     List a = product(EnumOne.values(), 
       EnumTwo.values(), EnumThree.values()); 
     System.out.println(a); 
    } 

    public static List<List<Enum>> product(Enum[]... enums) { 
     return product(new ArrayList<>(Arrays.asList(enums))); 
    } 

    public static List<List<Enum>> product(List<Enum[]> enums) { 
     if (enums.isEmpty()) { 
      //Trivial case of recursive function 
      return new ArrayList<>(); 
     } 
     //remove first element 
     Enum[] myEnums = enums.remove(0); 
     List<List<Enum>> out = new ArrayList<>(); 
     for (Enum e : myEnums) { 
      //call recursive 
      List<List<Enum>> list = product(enums); 
      for (List<Enum> list_enum : list) { 
       //for each list get from recursion adding element e 
       list_enum.add(0, e); 
       out.add(list_enum); 
      } 
      if(list.isEmpty()){ 
       List<Enum> list_enum = new ArrayList<>(); 
       list_enum.add(e); 
       out.add(list_enum); 
      } 
     } 
     enums.add(0, myEnums); //Backtraking 
     return out; 
    } 
} 

Risultato

[[Uno, Due, Tre], [Uno, due, ThreeMore], [onemore, due, tre], [onemore, Due, ThreeMore]]

+0

Non c'è bisogno di usare 'ArrayList' nelle dichiarazioni,' Lista' è sufficiente. È anche un codice non sicuro in più posizioni. Non sono nemmeno sicuro se questo conta come * efficiente * poiché memorizza l'intera (possibilmente lista di grandi dimensioni) in memoria. Come detto, può essere fatto nello spazio lineare. – dhke

+0

@dhke Ho risolto Elenco in dichiarazioni ..... sei fermo con l'uso della memoria è inefficiente in questo codice, e questo può essere migliorato –

+0

@dhke un algoritmo meglio è usato in [cartesiano-prodotto-di-insiemi-arbitrari- in-java] (http://stackoverflow.com/questions/714108/cartesian-product-of-arbitrary-sets-in-java), ma usano anche una lista intermedia come parte della soluzione –

0

Qui è una soluzione basata iteratore. In questo modo, il consumo di memoria non esploderà se funziona su molti tipi di enumerazione con carichi di costanti di enum. L'efficienza di esecuzione dovrebbe quindi andare bene (inoltre l'implementazione evita la ricorsione).

import java.util.Iterator; 
import java.util.List; 
import java.util.NoSuchElementException; 

public class EnumCombination implements Iterable<Enum<?>[]> { 

    private final Enum<?>[][] enumConstants; 
    private final int[] limits; 
    private final boolean emptyCombination; 

    public EnumCombination(final List<Class<? extends Enum<?>>> enums) { 
     this.limits = new int[enums.size()]; 
     this.enumConstants = new Enum<?>[enums.size()][]; 

     boolean empty = enums.isEmpty(); 
     for (int i = 0; i < enums.size(); i++) { 
      final Enum<?>[] enumElements = enums.get(i).getEnumConstants(); 
      enumConstants[i] = enumElements; 
      limits[i] = enumElements.length - 1; 
      empty |= enumElements.length == 0; 
     } 
     this.emptyCombination = empty; 
    } 

    @Override 
    public Iterator<Enum<?>[]> iterator() { 
     return new EnumCombinationIterator(); 
    } 

    private class EnumCombinationIterator implements Iterator<Enum<?>[]> { 
     private final int[] cursors = new int[limits.length]; 
     private boolean exhausted = emptyCombination; 

     @Override 
     public boolean hasNext() { 
      return !exhausted; 
     } 

     @Override 
     public Enum<?>[] next() { 
      if (exhausted) 
       throw new NoSuchElementException(); 

      final Enum<?>[] result = new Enum<?>[cursors.length]; 
      for (int i = 0; i < cursors.length; i++) { 
       result[i] = enumConstants[i][cursors[i]]; 
      } 
      moveCursors(); 

      return result; 
     } 

     private void moveCursors() { 
      for (int i = cursors.length - 1; i >= 0; i--) { 
       cursors[i] = cursors[i] == limits[i] ? 0 : cursors[i] + 1; 
       if (cursors[i] != 0) { 
        break; 
       } else if (i == 0) { 
        exhausted = true; 
       } 
      } 
     } 
    } 
} 

EnumCombination può essere utilizzato in questo modo:

import java.util.*; 

public class Main { 

    public enum EnumOne { 
     One, 
     OneMore 
    } 

    public enum EnumTwo { 
     Two 
    } 

    public enum EnumThree { 
     Three, 
     ThreeMore 
    } 

    public static void main(String... args) { 
     EnumCombination enumCombination = new EnumCombination(
       Arrays.asList(EnumOne.class, EnumTwo.class, EnumThree.class)); 

     for (final Enum<?>[] ec : enumCombination) { 
      System.out.println(Arrays.toString(ec)); 
     } 
    } 
} 

Ma, naturalmente, si potrebbe usare guava di cartesianProduct() così ...

Problemi correlati