位集合与整数/长整数的互相转换

61

如果我有一个整数需要进行位操作,如何将它加载到 java.util.BitSet 中?如何将其转换回 int 或 long 类型?我不太关心 BitSet 的大小 - 它始终为32或64位长。我只想使用 set()clear()nextSetBit()nextClearBit() 方法,而不是位运算符,但我找不到一个简单的方法来用数字类型初始化一个 bit set。


2
就我个人而言,我认为原始位操作是这里的最佳选择。它并不是很复杂,正如你所说,我也没有看到将int或long转换为BitSet的简单方法。 - Michael Myers
7个回答

65
下面的代码将一个 long 值创建为位集,反之亦然:
public class Bits {

  public static BitSet convert(long value) {
    BitSet bits = new BitSet();
    int index = 0;
    while (value != 0L) {
      if (value % 2L != 0) {
        bits.set(index);
      }
      ++index;
      value = value >>> 1;
    }
    return bits;
  }

  public static long convert(BitSet bits) {
    long value = 0L;
    for (int i = 0; i < bits.length(); ++i) {
      value += bits.get(i) ? (1L << i) : 0L;
    }
    return value;
  }
}

编辑:现在是双向的,@leftbrain:当然,你是对的。


1
FYI,这是按小端序创建位集。 - B T
4
对于 BitSet -> long,你应该真正使用 BitSet.nextSetBit() - charlie

48

如果位集中没有“1”,bs.toLongArray()[0]将抛出ArrayIndexOutOfBoundsException异常! - Qianyue

20

Java 7 提供了 BitSet.valueOf(byte[])BitSet.toByteArray() 方法。

如果你使用的是 Java 6 或者更早的版本,可以考虑使用 BigInteger. 如果性能不是主要瓶颈的话,BigIntegergetLowestSetBitsetBitclearBit 方法(后两个方法将创建一个新的 BigInteger 而非直接修改原始对象)。


5
为了以“流式”的方式从一个“小”BitSet中获取一个long,请参考以下内容:
long l = bitSet.stream()
        .takeWhile(i -> i < Long.SIZE)
        .mapToLong(i -> 1L << i)
        .reduce(0, (a, b) -> a | b);

反之亦然:

BitSet bitSet = IntStream.range(0, Long.SIZE - 1)
        .filter(i -> 0 != (l & 1L << i))
        .collect(BitSet::new, BitSet::set, BitSet::or);

注意:当然使用BitSet::valueOfBitSet::toLongArray更容易。

0
基本上直接从nextSetBit的文档中获取。
value=0;
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
 value += (1 << i)
 }

1
如果BitSet大于32或64位,则此方法将失败,在这种情况下,您需要在输出时处理int[]long[]。但是OP明确表示不关心,所以没问题。只有一些小错误:在使用long时,应该使用1L << i来防止溢出,并且像value |= 1L << i这样的OR操作就足够了。 - charlie

0
对于Kotlin,可以使用这些扩展。
BitSet到Int的扩展:
fun BitSet.toInt() =
    toLongArray()
        .getOrNull(0)
        ?.toInt()
        ?: 0

Int to BitSet扩展:

fun Int.toBitSet(size: Int): BitSet {
    val byteArray = byteArrayOf(toByte())

    return BitSet.valueOf(
        if (byteArray.size == size) byteArray
        else byteArray.copyOf(size))
}

使用示例:
val intValue = 1

val bitSetValue = intValue.toBitSet(size = 2)
println("bitSetValue: $bitSetValue")

val firstValue = bitSetValue.get(0)
println("firstValue: $firstValue")

val secondValue = bitSetValue.get(1)
println("secondValue: $secondValue")

bitSetValue.set(0, true)
bitSetValue.set(1, false)
println("bitSetValue: $bitSetValue")

val newIntValue = bitSetValue.toInt()
println("newIntValue: $newIntValue")

-3

你不是在寻找 public void set(int bit) 方法吗?


6
这将设置您提供的索引处的单个比特位。我想设置整数中设置的每个位。 - ataylor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接