2015-01-16 4 views
9

Что является самым элегантным способом генерации возможных логических комбинаций, учитывая максимальное количество логических элементов, которые вы хотите?Самый элегантный способ генерации возможных логических комбинаций

Ex:

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[] вместо boolean[].

Есть ли более удобный способ сделать это в одном слое с помощью Stream API?

+0

Просто начать с нуля и подсчитывают, используя целочисленный тип, как битовое поле? – chrylis

+0

Разве это не то, что он делает? Преобразование int-> двоичной строки, а затем char с помощью char для boolean. – 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()); 
} 

Это имеет преимущество быть менее плотным. В конце концов, это не код golf, APL или Perl, где цель, похоже, состоит в том, чтобы написать что-то самое краткое.Кодекс, который является менее плотным, часто, но не всегда, легче читать и понимать.

Есть некоторые нюансы в этом случае, хотя, я думаю. «Obj», испускаемый этапом mapToObj, равен long[], который определяется как тип параметра BitSet::valueOf. Это, в свою очередь, влияет на разрешение перегрузки! Если вы уже не знакомы с API BitSet, вы должны сами сделать вывод о том, что это такое. Поэтому в этом случае лучше иметь прямой вызов метода BitSet.valueOf(long[]).

С точки зрения производительности, которая не всегда является главным приоритетом, я думаю, что прямые вызовы методов, вероятно, работают лучше, чем цепочки из map операций. Передача значения через дополнительную операцию потока включает в себя, возможно, два вызова метода, плюс накладные расходы Lambda Metafactory требуют дополнительных лямбда (-ов). Кроме того, прямые вызовы методов, скорее всего, легче оптимизируются 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()); 
} 
Смежные вопросы