2015-01-16 82 views
9

給出您想要的最大數量的布爾值,生成可能的布爾組合的最優雅的方法是什麼?最優雅的方式來生成可能的布爾組合

例:

bool(1) -> [false], [true] 
bool(2) -> [false, false], [false, true], [true, false], [true, true] 
... 

這是我目前實施:

public static List<Boolean[]> bool(int n) { 
    return IntStream.range(0, (int) Math.pow(2, n)) 
        .mapToObj(i -> StringUtils.leftPad(Integer.toBinaryString(i), n, '0').chars().mapToObj(c -> c != '0').toArray(Boolean[]::new)) 
        .collect(Collectors.toList()); 
} 

但是我不太滿意的事實,我使用整數,然後映射到二進制與StringUtils.leftPadmap那返回Boolean[]而不是boolean[]

有沒有一種更好的方式來使用Stream API在單線程中完成它?

+0

從零剛開始和計數,使用整數類型作爲位域? – chrylis

+0

這不是他在做什麼?轉換int->二進制字符串,然後char字符布爾值。 – Todd

回答

3

嘗試這種情況:

boolean[] bitSetToArray(BitSet bs, int width) { 
    boolean[] result = new boolean[width]; // all false 
    bs.stream().forEach(i -> result[i] = true); 
    return result; 
} 

List<boolean[]> bool(int n) { 
    return IntStream.range(0, (int)Math.pow(2, n)) 
     .mapToObj(i -> bitSetToArray(BitSet.valueOf(new long[] { i }), n)) 
     .collect(toList()); 
} 

的關鍵是,BitSet上有一個stream()方法,它返回一比特的索引的流。這可以用於將true值設置爲boolean[]。還要注意(像Bubletan)可能有List<boolean[]>而不是List<Boolean[]>。也就是說,一個原始數組的列表boolean值而不是數組的列表框的Boolean值。 (這是因爲數組是參考類型,因此可以用作類型參數。)

最後,感謝Bubletan,其解決方案我通過添加bitSetToArray()來增強其解決方案。

UPDATE

srborlongan在評論提出以下是否可能會更好:

List<boolean[]> bool(int n) { 
    return IntStream.range(0, (int)Math.pow(2, n)) 
     .mapToObj(i -> new long[] { i }) 
     .map(BitSet::valueOf) 
     .map(bs -> bitSetToArray(bs, n)) 
     .collect(toList()); 
} 

它有被較不密集的優勢。畢竟,這不是代碼高爾夫,APL或Perl,其目標似乎是儘可能寫簡潔的方式。密度較低的代碼通常但並不總是更易於閱讀和理解。

我覺得在這種情況下有一些細微差別。由mapToObj階段發出的「obj」是long[],推斷該參數類型是BitSet::valueOf的參數類型。這反過來影響重載分辨率!除非你已經熟悉BitSet API,否則你必須自己做一些類型推斷來弄清楚這是幹什麼的。所以在這種情況下,直接調用BitSet.valueOf(long[])可能會更好。

在性能方面 - 這並不總是最重要的 - 我認爲直接方法調用可能比連鎖操作更好。通過額外的流操作傳遞一個值可能涉及兩個方法調用,另外Lambda Metafactory的開銷調用額外的lambda(s)。此外,直接方法調用可能更容易通過JIT進行優化,並且內聯,而不是通過流傳遞值。但我沒有證實這一點。

+1

將mapToObj函數拆分爲.mapToObj(i - > new long [] {i})。map(BitSet :: valueOf).map(bs - > bitSetToArray(bs,n))會更好嗎? – srborlongan

0

只有一個班輪 - 它給你一個Iterator不是List但是它演示計數和渲染計數的每一位爲boolean的原則。

public static Iterator<Boolean[]> bool(final int n) { 
    return new Iterator<Boolean[]>() { 
     final BigInteger max = BigInteger.ONE.shiftLeft(n); 
     BigInteger next = BigInteger.ZERO; 

     @Override 
     public boolean hasNext() { 
      return next.compareTo(max) < 0; 
     } 

     @Override 
     public Boolean[] next() { 
      Boolean[] b = new Boolean[n]; 
      for (int i = 0; i < n; i++) { 
       b[i] = next.testBit(i); 
      } 
      next = next.add(BigInteger.ONE); 
      return b; 
     } 

    }; 
} 

OldCurmudgeon沒有時間對這些新發明的Stream一樣的東西。他們永遠不會趕上 - 它只是一種時尚...離開我的草坪! :)

我寧願在Stream解決方案失敗的嘗試 - 我仍然不groking他們:

private static Boolean[] asBooleanArray(BigInteger n) { 
    int l = n.bitLength(); 
    Boolean[] b = new Boolean[l]; 
    for (int i = 0; i < l; i++) { 
     b[i] = n.testBit(i); 
    } 
    return b; 
} 

    List<Boolean[]> bools = 
      Stream.<BigInteger>iterate(
        BigInteger.ZERO, 
        i -> i.add(BigInteger.ONE)) 
      .map(n -> asBooleanArray(n)) 
      .collect(Collectors.toList()); 

我有端接infnite Stream問題。

2

嘗試了一些東西。不使用Stream API來處理所有事情。雖然我認爲不可能使用它創建boolean[]。沒有用太多,所以我可能是錯的。

public static List<boolean[]> bool(int n) { 
    return IntStream.range(0, 1 << n) 
      .mapToObj(i -> BitSet.valueOf(new long[] {i})) 
      .map(bs -> { 
       boolean[] a = new boolean[n]; 
       for (int i = 0; i < n; i++) { 
        a[n - i - 1] = bs.get(i); 
       } 
       return a; 
      }) 
      .collect(Collectors.toList()); 
} 
1

如果它必須是Stream S:

public static List<boolean[]> bool(int n) { 
    return IntStream.range(0, 1<<n).mapToObj(
     i->IntStream.range(0, n) 
      .collect(()->new boolean[n], (ba,j)->ba[j]=((i>>>j)&1)!=0, 
      (x,y)->{throw new UnsupportedOperationException();}) 
    ).collect(Collectors.toList()); 
} 

我離開了未使用合併功能兩個boolean[]陣列,雖然它可以提供這樣的功能。但是,尤其是內Stream代碼是不是一個巨大的勝利相比,直接的循環:

public static List<boolean[]> bool(int n) { 
    return IntStream.range(0, 1<<n).mapToObj(i-> { 
     boolean[] ba=new boolean[n]; 
     for(int j=0; j<n; j++) ba[j]=((i>>>j)&1)!=0; 
     return ba; 
    }).collect(Collectors.toList()); 
}