簡體   English   中英

如何在Java中生成具有N個可能元素(M> N)的數組列表(都具有長度M)?

[英]How to generate a list of arrays (all have the length M) with N possible elements (M > N) in Java?

例如,如果元素為{1, 2} (n = 2)m = 3 ,則該方法應生成一個數組列表,如{[1,1,1],[1,1,2],[1,2,1],[2,1,1],[1,2,2],[2,2,1],[2,1,2],[2,2,2]}

我知道Python可以執行y = itertools.product((1, 2), repeat=3) ,但是我如何有效地在Java中實現它。 我已嘗試提供一些初始List並使用以下內容來獲得我想要的但時間復雜度太高而且當輸入很大時性能非常糟糕。

public static List<List<Integer>> permute (List<Integer> list, int need) {

    List<List<Integer>> result = new ArrayList<>();
    if (need--==0) {
        result.add(list);
        return result;
    }
    for (int current : list)
        insert(permute(list,need), current, result);
    return result;
}


private static void insert(List<List<Integer>> currentLists, int currentInt, List<List<Integer>> list) {
    for (List<Integer> currentList : currentLists) {
        int size = currentList.size();
        for (int i = 0; i <= size; i++) {
            List<Integer> newList = new LinkedList<>();
            newList.addAll(currentList);
            newList.add(i, currentInt);
            list.add(newList);
        }
    }
}

實際上你無法降低復雜性。 您需要執行的最少操作數是創建列表。 列表的數量不能減少(它總是等於n ^ m)並且這些列表的創建是在執行期間花費大量時間的事情。

我添加了我的代碼,我曾經做過一些測試,如果它可以幫助你。

//Main method who generate the resultList
public static ArrayList<ArrayList<Integer>> generateList(ArrayList<Integer> elements, int size) {
    //Initialisation
    ArrayList<ArrayList<Integer>> resultList = new ArrayList<ArrayList<Integer>>();
    ArrayList<Integer> indexes = new ArrayList<Integer>();

    for(int i = 0; i < size;i++){
       indexes.add(0);
    }


    resultList.add(generateCurrentList(indexes,elements)); //Add the first element

    for(int i = 0; i < Math.pow(elements.size(),size)-1;i++){ //Add the other elements by incrementing indexes at each add
        incrementIndexes(indexes,elements.size());
        resultList.add(generateCurrentList(indexes,elements));
    }

    return resultList;  
}


//Increment indexes
public static void incrementIndexes(ArrayList<Integer> indexes,int nbrElements){
    indexes.set(indexes.size()-1, indexes.get(indexes.size()-1)+1); //Increment the last index
    for(int i = indexes.size()-1;i > 0;i--){//For each index increment the previous one if the current is greater than the number of element
        if(indexes.get(i)==nbrElements)
            indexes.set(i-1, indexes.get(i-1)+1);
    }
    for(int i = 0;i < indexes.size();i++){
        indexes.set(i, indexes.get(i)%nbrElements);
    }
}

//Generate an arrayList using the current indexes and the list of elements
public static ArrayList<Integer> generateCurrentList(ArrayList<Integer> indexes,ArrayList<Integer> elements){
    ArrayList<Integer> currentList = new ArrayList<Integer>();
    for(int i = 0; i < indexes.size();i++){
        currentList.add(elements.get(indexes.get(i)));
    }
    return currentList;
}`

使用libary StreamEx解決方案可能如下所示:

    List<Integer> list = Arrays.asList(1, 2);
    int need = 3;
    StreamEx<List<Integer>> product = StreamEx.cartesianPower(need, list);

您可以使用並行處理或僅消耗部分延遲生成的結果來獲得效率。


普通舊java中的另一個懶惰解決方案將創建Iterator,它可以懶惰地生成排列

class Permutator<T> implements Iterable<List<T>> {

    final List<T> items;
    final int homMuch;

    Permutator(List<T> items, int homMuch) {
        this.items = items;
        this.homMuch = homMuch;
    }

    @Override
    public Iterator<List<T>> iterator() {
        return new Iterator<List<T>>() {
            static final int OVERFLOW = -1;
            final int[] permutation = new int[homMuch];
            final int max = items.size();

            @Override
            public boolean hasNext() {
                for (int item : permutation) {
                    if (item == OVERFLOW) {
                        return false;
                    }
                }
                return true;
            }

            @Override
            public List<T> next() {
                ArrayList<T> result = new ArrayList<>(permutation.length);
                for (int index : permutation) {
                    result.add(items.get(index));
                }

                inc(permutation, 0);           // generate next permutation

                return result;
            }

            private void inc(int[] indexes, int index) {
                if (index >= indexes.length) {
                    for (int i = 0; i < indexes.length; i++) {
                        indexes[i] = OVERFLOW;
                    }
                    return;
                }
                int nextValue = indexes[index] + 1;
                if (nextValue < max) {
                    indexes[index] = nextValue;
                } else {
                    indexes[index] = 0;
                    inc(indexes, index + 1);
                }
            }

        };
    }
}

這種發生器可以在循環中懶惰地使用

List<String> list = Arrays.asList("one", "two");
int need = 3;
for (List<String> permutation : new Permutator<>(list, need)) {
    System.out.println(permutation);
}

輸出:

[one, one, one]
[two, one, one]
[one, two, one]
[two, two, one]
[one, one, two]
[two, one, two]
[one, two, two]
[two, two, two]

這是一種方法。 我初始化行。 然后我按列填充每一行。 讓它在右邊迭代有點棘手,但沒什么太難的。

public class GeneratePermutations {

  public static void main(String[] args) {
      int[] inputs = {1, 2, 3};
      List<int[]> results = permute(inputs, 4);
      printResults(results);
  }

  private static List<int[]> permute(int[] inputs, int size) {
      // set up the rows
      List<int[]> results = new ArrayList<int[]>();
      int count = (int)Math.pow(inputs.length, size);
      for (int row = 0; row < count; row++) {
          results.add(new int[size]);
      }

      // fill the rows by column
      for (int column = 0; column < size; column++) {
          permute(results, inputs, column);
      }

      return results;
  }

  private static void permute(List<int[]> results, int[] inputs, int column) {
      int inputIndex = 0;
        int input = inputs[inputIndex];

      // How often should we increment through the inputs?
      // If we use "column" as the exponent then we iterate more frequently
      // on the left (e.g. [1,1,1], [2,1,1], [1,2,1], etc.)
      // In order to iterate more right to left, use "size - column"
      // as the exponent.
      int incrIndex = 0;
      final int exponent = results.get(0).length - 1 - column;
      final int incrLength = (int)Math.pow(inputs.length, exponent);

      for (int[] result : results) {
          result[column] = input;

          // How often we step through the inputs depends on the column.
          incrIndex = (incrIndex + 1) % incrLength;
          if (incrIndex == 0) {
              inputIndex = (inputIndex + 1) % inputs.length;
              input = inputs[inputIndex];
          }
      }
  }

  private static void printResults(List<int[]> results) {
      for (int[] result : results) {
          System.out.println(Arrays.toString(result));
      }
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM