【问题标题】:Most elegant way to generate possible boolean combinations生成可能的布尔组合的最优雅方式
【发布时间】:2015-01-16 22:49:02
【问题描述】:

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

例如:

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 和返回Boolean[] 而不是boolean[]map 映射到二进制。

有没有更好的方法来使用 Stream API 在单行中做到这一点?

【问题讨论】:

  • 只是从零开始往上数,使用整数类型作为位域?
  • 这不是他在做的吗?将 int->binary 字符串,然后 char by char 转换为 boolean。
  • 很惊讶在公共空间中没有这样的方法

标签: java java-8 java-stream


【解决方案1】:

试试这个:

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&lt;boolean[]&gt; 而不是 List&lt;Boolean[]&gt;。也就是说,原始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,其目标似乎是尽可能以最简洁的方式编写一些东西。不那么密集的代码通常(但并非总是)更容易阅读和理解。

我认为在这种情况下存在一些细微差别。 mapToObj阶段发出的“obj”是long[],推断为BitSet::valueOf的参数类型。这反过来会影响重载解决方案!除非您已经非常熟悉 BitSet API,否则您必须自己进行一些类型推断才能弄清楚它在做什么。所以在这种情况下,最好直接调用BitSet.valueOf(long[])

就性能而言——这并不总是最重要的——我认为直接方法调用可能比map 操作链执行得更好。通过额外的流操作传递值可能涉及两个方法调用,以及 Lambda Metafactory 调用额外 lambda(s) 的开销。此外,与通过流传递值相比,直接方法调用可能更容易被 JIT 优化和内联。但我还没有验证任何这些。

【讨论】:

  • 将mapToObj函数拆分成.mapToObj(i -> new long[] { i }).map(BitSet::valueOf).map(bs -> bitSetToArray(bs, n)) ?
【解决方案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());
}

【讨论】:

    【解决方案3】:

    如果必须是Streams:

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

    【讨论】:

      【解决方案4】:

      只有一种单行 - 它给你一个Iterator而不是List,但它演示了计数并将计数的每一位呈现为@987654323的原理@。

      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 东西。他们永远不会流行 - 这只是一种时尚......离开我的草坪! :)

      我对@9​​87654327@ 解决方案的尝试相当失败 - 我仍然没有摸索他们:

      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 时遇到问题。

      【讨论】:

        猜你喜欢
        • 2019-11-03
        • 1970-01-01
        • 2011-04-06
        • 2015-03-22
        • 1970-01-01
        • 1970-01-01
        • 2010-11-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多