最优雅的方式来生成可能的布尔组合

use*_*315 11 java java-8 java-stream

在给定所需布尔值的最大数量的情况下,生成可能的布尔组合的最优雅方法是什么?

例如:

bool(1) -> [false], [true]
bool(2) -> [false, false], [false, true], [true, false], [true, true]
...
Run Code Online (Sandbox Code Playgroud)

这是我目前的实施:

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());
}
Run Code Online (Sandbox Code Playgroud)

但是我不满意我使用整数,然后映射到二进制,StringUtils.leftPad并map返回一个Boolean[]而不是一个boolean[].

使用Stream API在单线程中有更好的方法吗?

Stu*_*rks 5

试试这个:

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());
}
Run Code Online (Sandbox Code Playgroud)

关键是它BitSet有一个stream()方法,它返回一位索引流.这可用于将true值设置为a 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());
}
Run Code Online (Sandbox Code Playgroud)

它确实具有密度较低的优点.毕竟,这不是代码高尔夫,APL或Perl,其目标似乎是尽可能以最简洁的方式编写代码.密度较低的代码通常(但并非总是)更容易阅读和理解.

我认为,在这种情况下有一些细微差别.mapToObj舞台发出的"obj"被long[]推断为参数类型BitSet::valueOf.这又会影响重载分辨率!除非你已经非常熟悉BitSetAPI,否则你必须自己做一些类型推断来弄清楚它在做什么.所以在这种情况下,直接调用方法可能会更好BitSet.valueOf(long[]).

在性能方面 - 这并不总是最重要的 - 我认为直接方法调用可能比一系列map操作表现更好.通过额外的流操作传递值可能涉及两个方法调用,以及Lambda Metafactory调用额外lambda的开销.此外,直接方法调用可能更容易通过JIT和内联优化,而不是通过流传递值.但我还没有证实这一点.