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

时间:2015-01-16 22:49:03

标签: java java-8 java-stream

根据您想要的最大布尔数,生成可能的布尔组合的最优雅方法是什么?

前:

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.leftPad映射到二进制文件,而map则返回Boolean[]而不是{{1} }}

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

4 个答案:

答案 0 :(得分: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());
}

关键是BitSet上有一个stream()方法,它返回一位索引流。这可用于将true值设置为boolean[]。另请注意(如Bubletan),可以使用List<boolean[]>代替List<Boolean[]>。也就是说,原始boolean值数组的列表而不是盒装Boolean值数组的列表。 (这是因为数组是引用类型,因此可以用作类型参数。)

最后,感谢Bubletan,我通过添加bitSetToArray()扩充了其解决方案。

<强>更新

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,其目标似乎是尽可能以最简洁的方式编写内容。密度较低的代码通常(但并非总是)更易于阅读和理解。

我认为在这种情况下有一些细微差别。 &#34; obj&#34;由mapToObj阶段发出的是long[],其被推断为BitSet::valueOf的参数类型。这又会影响重载分辨率!除非您已经熟悉BitSet API,否则您必须自己做一些类型推断,以弄清楚这是做什么的。因此,在这种情况下,对BitSet.valueOf(long[])进行直接方法调用可能会更好。

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

答案 1 :(得分:2)

试了一下。我们不会将Stream API用于所有内容..虽然我不认为可以使用它来创建boolean[]。 Haven没有使用它,所以我可能错了。

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

答案 2 :(得分: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());
}

答案 3 :(得分: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解决方案的尝试失败了 - 我仍然没有动摇它们:

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

我在终止无效Stream时遇到了问题。