2015-05-01 65 views
6

是否有一種有效的方法來查找Java中多個枚舉之間的所有可能組合?查找所有可能的枚舉組合

考慮以下三個枚舉 -

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

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

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

我想輸出到這些多個枚舉即

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

希望能找到應對它的有效途徑之間產生的所有可能的組合。

謝謝

+0

定義「高效」 – David

+0

您正在尋找的東西比嵌套好循環?目前還不清楚你在問什麼 – Misha

+0

儘可能少遞歸 – JUG

回答

-1

這樣的事情如何?

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); 
     } 
    } 
} 

你會使用這樣的

printAll(allMyEnumClassesList, 0, null); 
+0

將值放入一個字符串中。我不太確定那是什麼要求。 – dhke

+0

@dhke這就是解釋。無論哪種方式,如果需要可以改變輸出。不需要是String [],可以是Object []。當它得到一個組合時它不需要打印(如果需要,它可以將它存儲在某個地方)。 –

0

的算法的複雜度爲O(NxMxK .... XZ)如果我錯了,我不知道這是否一個 「有效的方式」 ....我作爲回溯法溶液

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; 
    } 
} 

結果

使用

[[一,二,三],[一,二,ThreeMore],[OneMore,二,三],[OneMore,二,ThreeMore]]

+0

不需要在聲明中使用'ArrayList','List'就足夠了。這也是多個地點不安全的代碼。我也不確定這是否作爲*有效率*,因爲它將整個(可能是大的列表)存儲在內存中。如上所述,它可以在線性空間中完成。 – dhke

+0

@dhke我在聲明中修復了列表.....你對內存的使用在這段代碼中效率很低,這可以改進 –

+0

@dhke更好的算法用於[cartesian-product-of-arbitrary-sets- in-java](http://stackoverflow.com/questions/714108/cartesian-product-of-arbitrary-sets-in-java),但他們也使用中間列表作爲解決方案的一部分 –

0

下面是一個基於迭代器的解決方案。這樣,如果內存消耗在枚舉常量負載的許多枚舉類型上運行,它不會發生爆炸。因此執行效率應該很好(此外,執行避免了遞歸)。

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可以像這樣使用:

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)); 
     } 
    } 
} 

但是,當然,可以使用番石榴的​​以及...