2015-01-16 6 views
9

Was ist die eleganteste Art, die möglichen booleschen Kombinationen zu generieren, wenn man die maximale Anzahl an booleschen Werten wählt?Der eleganteste Weg, um mögliche boolesche Kombinationen zu generieren

Ex:

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

Dies ist meine aktuelle Implementierung:

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

Jedoch habe ich mit der Tatsache nicht zufrieden bin, dass ich ganze Zahlen verwenden, dann auf binäre Karte mit StringUtils.leftPad und die map, dass gibt eine Boolean[] anstelle einer boolean[] zurück.

Gibt es einen schöneren Weg, dies in einem Einzeiler mit der Stream API zu tun?

+0

Starten Sie einfach von Null und zählen, einen Integer-Typ als Bitfeld verwendet? – chrylis

+0

Ist das nicht das, was er tut? Konvertieren von int-> binary string und dann char von char zu boolean. – Todd

Antwort

3

Dieses versuchen:

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

Der Schlüssel ist, dass ein BitSetstream() Verfahren darauf hat, die einen Strom von Indizes der one-Bits zurückgibt. Dies kann verwendet werden, um true Werte in boolean[] zu setzen. Beachten Sie auch, dass (wie bei Bubletan) ein List<boolean[]> anstelle von List<Boolean[]> möglich ist. Das heißt, eine Liste von Arrays von primitiven boolean Werten anstelle einer Liste von Arrays von boxed Werten. (Dies liegt daran, dass Arrays Referenztypen sind und daher als Typargument verwendet werden können.)

Schließlich, dank Bubletan, deren Lösung ich ergänzt durch Hinzufügen bitSetToArray().

UPDATE

srborlongan in einem Kommentar gefragt, ob die folgenden besser sein könnte:

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

es den Vorteil, dass sie weniger dicht hat. Schließlich ist dies nicht Code Golf, APL oder Perl, wo das Ziel zu sein scheint, etwas möglichst knappe zu schreiben.Code, der weniger dicht ist, ist oft, aber nicht immer einfacher zu lesen und zu verstehen.

Es gibt jedoch einige Nuancen in diesem Fall, denke ich. Das von der Stufe mapToObj ausgegebene "obj" ist long[], was als der Parametertyp von BitSet::valueOf gewertet wird. Dies wirkt sich wiederum auf die Überlastauflösung aus! Es sei denn, Sie sind bereits vertraut mit der BitSet API, müssen Sie ein bisschen Typ Rückschluss selbst tun, um herauszufinden, was das tut. In diesem Fall ist es besser, einen direkten Methodenaufruf an BitSet.valueOf(long[]) zu haben.

In Bezug auf die Leistung - die nicht immer oberste Priorität hat - denke ich, dass direkte Methodenaufrufe wahrscheinlich besser als eine Kette von map Operationen durchführen. Das Übergeben eines Werts durch eine zusätzliche Datenstromoperation umfasst möglicherweise zwei Methodenaufrufe und zusätzlich den Overhead des Lambda-Metafactory-Aufrufs für die zusätzlichen Lambda (s). Darüber hinaus werden direkte Methodenaufrufe wahrscheinlich durch das JIT und inlined einfacher als durch das Übergeben von Werten durch den Stream optimiert. Aber ich habe nichts davon verifiziert.

+1

Wäre es besser, die mapToObj-Funktion in .mapToObj zu teilen (i -> new long [] {i}). Map (BitSet :: valueOf) .map (bs -> bitSetToArray (bs, n))? – srborlongan

0

Nur Art von ein Einzeiler - und es gibt Ihnen ein Iterator keine List aber es zeigt das Prinzip des Zählens und jedes Bit der Zählung als boolean Rendering.

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 hat keine Zeit für diese neumodischen Stream thingies. Sie werden sich nie durchsetzen - es ist nur eine Modeerscheinung ... geh von meinem Rasen !! :)

Mein gescheitert eher Versuch einer Stream Lösung - ich bin immer noch nicht groking sie:

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

ich Probleme habe ein infnite Abschluss Stream.

2

Versuchte etwas. Verwendet nicht die Stream-API für alles. Obwohl ich glaube nicht, dass es möglich ist, eine boolean[] damit zu erstellen. Hab es nicht oft benutzt, damit ich falsch liege.

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

Wenn es hat Stream s sein:

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

ich für zwei boolean[] Arrays den ungenutzten Merge-Funktion weggelassen, obwohl es möglich ist, eine solche Funktion zur Verfügung zu stellen. Aber vor allem die innere Stream Code ist kein großer Gewinn im Vergleich zu einem Straight-Forward-Schleife:

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()); 
} 
Verwandte Themen