在Java中,如何以整数的反向二进制形式获取1的位置?

在Java中,如何以整数的反向二进制形式获取1的位置?,java,binary,bit-manipulation,Java,Binary,Bit Manipulation,我有一个遗留应用程序,它接受一个整数,将其转换为二进制字符串,反转该字符串,然后获取位(1)的位置作为整数列表。例如: 6 -> "110" -> "011" -> (2,3) 7 -> "111" -> "111" -> (1,2,3) 8 -> "1000" -> "0001" -> (4) 在现代Java中,没有字符串操作,用什么简洁明了的方法来实现这一点?字符串之间的转换对我来说似乎是浪费,而且我知道没有简单的方法可以翻转字符串(

我有一个遗留应用程序,它接受一个整数,将其转换为二进制字符串,反转该字符串,然后获取位(1)的位置作为整数列表。例如:

6 -> "110" -> "011" -> (2,3) 
7 -> "111" -> "111" -> (1,2,3)
8 -> "1000" -> "0001" -> (4)

在现代Java中,没有字符串操作,用什么简洁明了的方法来实现这一点?字符串之间的转换对我来说似乎是浪费,而且我知道没有简单的方法可以翻转字符串(no
String.reverse()
)。你可以只计算指数

String str = Integer.toBinaryString(num);
int len = str.length();
List<Integer> list = new ArrayList<>();
for (int i=0; i < len; i ++) {
  if (str.charAt(i) == '1') list.add(len - 1 - i);
}
String str=Integer.toBinaryString(num);
int len=str.length();
列表=新的ArrayList();
对于(int i=0;i
您只需测试位,而无需将整数转换为字符串:

列出一个位置(int输入){
List onePositions=new ArrayList();
用于(int位=0;位<32;位++){

如果(输入)&(1只需依次检查位:

List<Integer> bits(int num) {
  List<Integer> setBits = new ArrayList<>();
  for (int i = 1; num != 0; ++i, num >>>= 1) {
    if ((num & 1) != 0) setBits.add(i);
  }
  return setBits;
}

只需使用String类的
indexOf
函数

public class TestPosition {
    public static void main(String[] args) {
        String word = "110"; // your string
        String guess = "1"; // since we are looking for 1
        int totalLength = word.length();
        int index = word.indexOf(guess);
        while (index >= 0) {
            System.out.println(totalLength - index);
            index = word.indexOf(guess, index + 1);
        }
    }
}

您可以使用此解决方案:

    static List<Integer> convert(int input) {
        List<Integer> list = new ArrayList<>();
        int counter = 1;
        int num = (input >= 0) ? input : Integer.MAX_VALUE + input + 1;
        while (num > 0) {
            if (num % 2 != 0) {
                list.add(counter);
            }
            ++counter;
            num /= 2;
        }
        return list;
    }

我当然更喜欢安迪自己的答案,即使一开始它看起来很神秘。但是因为这里还没有人有关于streams的答案(即使它们在这里完全不合适):

公共列表getList(intx){
String str=Integer.toBinaryString(x);
最终字符串反转=新的StringBuilder(str).reverse().toString();
返回IntStream.range(1,str.length()+1)
.filter(i->reversed.charAt(i-1)='1')
.boxed()
.collect(Collectors.toList());
}
既然您编写了“现代Java”,这就是如何使用流来实现它的方法(Java 8或更好):

印刷品

[1, 2, 3]

一个愚蠢的回答,只是为了多样化:

BitSet bs = BitSet.valueOf(new long[] {0xFFFFFFFFL & input});
List<Integer> setBits = new ArrayList<>();
for (int next = -1; (next = bs.nextSetBit(next + 1)) != -1;) {
  setBits.add(next + 1);
}
bitsetbs=BitSet.valueOf(新长[]{0xffffffffffl&input});
List setbit=new ArrayList();
对于(int next=-1;(next=bs.nextSetBit(next+1))!=-1;){
setbit.add(下一步+1);
}
(感谢pero_hero指出WJS的回答中需要遮罩)

只是为了好玩:

Pattern one = Pattern.compile("1");
List<Integer> collect = one.matcher(
             new StringBuilder(Integer.toBinaryString(value)).reverse())
            .results()
            .map(m -> m.start() + 1)
            .collect(Collectors.toList());
System.out.println(collect);
patterone=Pattern.compile(“1”);
List collect=one.matcher(
新的StringBuilder(Integer.toBinaryString(value)).reverse()
.结果()
.map(m->m.start()+1)
.collect(Collectors.toList());
系统输出打印项次(收集);

给定原始整数,返回一个包含位位置的列表

static List<Integer> bitPositions(int v) {
     return BitSet.valueOf(new long[]{v&0xFF_FF_FF_FFL})
                .stream()
                .mapToObj(b->b+1)
                .collect(Collectors.toList());
}
静态列表位位置(int v){
返回BitSet.valueOf(新长[]{v&0xFF\u FF\u FFL})
.stream()
.mapToObj(b->b+1)
.collect(Collectors.toList());
}
或者如果你想做位移位

static List<Integer> bitPositions(int v ) {
    List<Integer> bits  = new ArrayList<>();
    int pos = 1;
    while (v != 0) {
        if ((v & 1) == 1) {
            bits.add(pos);
        }
        pos++;
        v >>>= 1;
    }
    return bits;

}

静态列表位位置(int v){
列表位=新的ArrayList();
int pos=1;
而(v!=0){
如果((v&1)==1){
位添加(pos);
}
pos++;
v>>=1;
}
返回位;
}
或者如果需要:

String strValue = Integer.toBinaryString(value);
List<Integer> collect2 = strValue.codePoints()
           .collect(ArrayList<Integer>::new,
                   (l, v) -> l.add(v == '1' ? strValue.length() - l.size() : -1), 
                   (l1, l2) -> l1.addAll(l2)).stream()
           .filter(e -> e >= 0)
           .sorted()
           .collect(toList());
String strValue=Integer.toBinaryString(值);
List collect2=strValue.codePoints()
.collect(数组列表::新建,
(l,v)->l.add(v=='1'?strValue.length()-l.size():-1),
(l1,l2)->l1.addAll(l2)).stream()
.过滤器(e->e>=0)
.已排序()
.collect(toList());

我可以提出一个纯粹的位解决方案吗

static List<Integer> onesPositions(int input)
{
    List<Integer> result = new ArrayList<Integer>(Integer.bitCount(input));

    while (input != 0)
    {
        int one = Integer.lowestOneBit(input);
        input = input - one;
        result.add(Integer.numberOfTrailingZeros(one));
    }

    return result;
}
静态列表一个位置(int输入)
{
列表结果=新的ArrayList(整数.位计数(输入));
while(输入!=0)
{
int one=整数。低位(输入);
输入=输入-一;
结果.add(整数.numberoftrailingzero(一));
}
返回结果;
}
该解决方案在算法上是最优的:

  • 单个内存分配,使用
    Integer.bitCount
    预先适当调整
    ArrayList
    的大小
  • 循环迭代的最小次数,每组1位
  • 内部循环相当简单:

    • Integer.lowstonebit
      仅返回输入集最低位的
      int
    • 输入-一个
      从输入中“取消设置”该位,用于下一次迭代
    • Integer.numberoftrailingzero
      以二进制形式计算尾随零的数量,有效地为我们提供最低1位的索引

    1值得注意的是,这可能不是编译后的最佳方式,相反,基于
    位计数的显式
    0..n
    循环更容易在JIT中展开。

    流版本的@Matthieu M。答案:

     List<Integer> list = IntStream.iterate(value, (v) -> v != 0, (v) -> v & (v - 1))
                    .mapToObj(val -> Integer.numberOfTrailingZeros(val) + 1)
                    .collect(toList());
    
    List List=IntStream.iterate(值,(v)->v!=0,(v)->v&(v-1))
    .mapToObj(val->Integer.numberOfTrailingZeros(val)+1)
    .collect(toList());
    
    不过,您不需要转换为字符串。@Andy Turner true,我只是不知道如何使用位移位。我认真地问自己:为什么?所有的解决方案都会以某种方式检查是否有位,然后以某种方式存储索引。也许不需要字符串转换,但按照今天的标准,我怀疑它是否对索引有多大影响性能。注意:
    新的StringBuilder.reverse().toString()
    可用于反转字符串。在这里使用字符串@maio290在概念上是不可靠的。性能与此无关(尽管这是一个结果,如果这是一个频繁的操作,性能实际上可能会变得相关)。这有什么用?我想不出它的实际用途。@inetphantom,如我所说,legacy system。这实际上是数据库中一个非常特殊的“外键”。整数对一组ID编号进行编码,以便在数据库表中查找。看起来不错。我从不使用这些二进制/位操作,因此我永远记不住它们。显然:-)用字符串做这件事太糟糕了。这个问题有很多很好的答案!我认为这个问题中的迭代,用shift-right操作符,非常聪明。而且
    static List<Integer> bitPositions(int v) {
         return BitSet.valueOf(new long[]{v&0xFF_FF_FF_FFL})
                    .stream()
                    .mapToObj(b->b+1)
                    .collect(Collectors.toList());
    }
    
    static List<Integer> bitPositions(int v ) {
        List<Integer> bits  = new ArrayList<>();
        int pos = 1;
        while (v != 0) {
            if ((v & 1) == 1) {
                bits.add(pos);
            }
            pos++;
            v >>>= 1;
        }
        return bits;
    
    }
    
    
    String strValue = Integer.toBinaryString(value);
    List<Integer> collect2 = strValue.codePoints()
               .collect(ArrayList<Integer>::new,
                       (l, v) -> l.add(v == '1' ? strValue.length() - l.size() : -1), 
                       (l1, l2) -> l1.addAll(l2)).stream()
               .filter(e -> e >= 0)
               .sorted()
               .collect(toList());
    
    static List<Integer> onesPositions(int input)
    {
        List<Integer> result = new ArrayList<Integer>(Integer.bitCount(input));
    
        while (input != 0)
        {
            int one = Integer.lowestOneBit(input);
            input = input - one;
            result.add(Integer.numberOfTrailingZeros(one));
        }
    
        return result;
    }
    
     List<Integer> list = IntStream.iterate(value, (v) -> v != 0, (v) -> v & (v - 1))
                    .mapToObj(val -> Integer.numberOfTrailingZeros(val) + 1)
                    .collect(toList());