对列表中的多个 BigInteger 值执行逻辑与运算 Java
Perform logical AND operation on multiple BigInteger Values in lists Java
我正在尝试开发一种在多个 BigInteger 值之间执行逻辑 AND 运算的有效方法。例如,让我们考虑下面的片段:
public static void main(String[] args) {
List<BigInteger> a = Arrays.asList(new BigInteger("1000",2), new BigInteger("101",2), new BigInteger("111",2));
List<BigInteger> b = Arrays.asList(new BigInteger("10",2), new BigInteger("10110",2), new BigInteger("10011",2));
List<BigInteger> c = Arrays.asList(new BigInteger("1",2), new BigInteger("10110",2), new BigInteger("11110",2));
List<BigInteger> dd = IntStream.range(0, a.size())
.mapToObj(i -> a.get(i).and(b.get(i)).and(c.get(i)))
.collect(Collectors.toList());
System.out.println(dd);
//OUTPUT = [0, 4, 2]
}
但是,此解决方案的问题是 map 函数接受的值的静态数量。让我们假设一个包含多个列表(也超过 3 个)的 ArrayList,我该如何更改之前的解决方案?
public static void main(String[] args) {
List<BigInteger> a = Arrays.asList(new BigInteger("1000",2), new BigInteger("101",2), new BigInteger("111",2));
List<BigInteger> b = Arrays.asList(new BigInteger("10",2), new BigInteger("10110",2), new BigInteger("10011",2));
List<BigInteger> c = Arrays.asList(new BigInteger("1",2), new BigInteger("10110",2), new BigInteger("11110",2));
ArrayList<List<BigInteger>> collection = new ArrayList<List<BigInteger>>();
collection.add(a);
collection.add(b);
collection.add(c);
List<BigInteger> dd = null;
//......
System.out.println(dd);
}
请注意,我决定选择采用 stream.map(),因为列表中 BigInteger 值的数量可能很大(数千个值),我想利用 parallelStream() 来执行此操作。但是,我接受任何有效执行此操作的建议。
如果我正确理解了您的尝试,那么这就是 Stream
的 reduce
方法的用途。
例如,以下应该有效:
final List<BigInteger> result = IntStream.range(0, a.size())
.mapToObj(i -> collection.stream()
.map(l -> l.get(i)) // Map to the i'th element of all streams.
// This line is the trick. It effectively performs '&' on all elements
// in the mapped stream. The first argument is the 'identity' element
// of '&'-ing, which is a binary 11111...
// -1 Behaves like this (although I have no idea how it works for
// BigInteger, it seems to give the right values for the things you've
// given as examples).
.reduce(BigInteger.ZERO.subtract(BigInteger.ONE), BigInteger::and))
.collect(Collectors.toList());
注意:如果您在这里寻求效率(这对您的用例确实很重要),那么请考虑您是否需要 BigInteger
。忽略符号(因为你正在进行按位运算)long
数组会给你 64
位,很容易 涵盖你在示例中给出的所有内容(和常见用例中的大多数数字)并且会更快。
你可以试试这样的
List<BigInteger> dd = IntStream.range(0, a.size())
.mapToObj(i ->
collection.stream()
.map(col -> col.get(i))
.reduce(BigInteger::and)
.get())
.collect(Collectors.toList());
替代答案的灵感来自 Stanislav Bashkyrtsev's comment, which uses BitSet
s。
public static void main(String[] args) {
final List<BitSet> a = Arrays.asList(
BitSet.valueOf(new long[] {0b1000L}),
BitSet.valueOf(new long[] {0b101L}),
BitSet.valueOf(new long[] {0b111L})
);
final List<BitSet> b = Arrays.asList(
BitSet.valueOf(new long[] {0b10L}),
BitSet.valueOf(new long[] {0b1_0110L}),
BitSet.valueOf(new long[] {0b1_0011L})
);
final List<BitSet> c = Arrays.asList(
BitSet.valueOf(new long[] {0b1L}),
BitSet.valueOf(new long[] {0b1_0110L}),
BitSet.valueOf(new long[] {0b1_1110L})
);
final List<List<BitSet>> bitSets = Arrays.asList(a, b, c);
final List<BitSet> results = IntStream.range(0, a.size())
.mapToObj(i -> bitSets.stream().map(l -> l.get(i))
// First argument of reduce is identity element, it needs
// to be a BitSet with at least as many bits as any input
// ones which are all set. In this case, 64 bits are
// used, initialised by a long. If you have /more/ bits
// needed, then create one with new BitSet(bitCount);
// and then set all bits.
.reduce(BitSet.valueOf(new long[] {0xFFFF_FFFF_FFFF_FFFFL}), (_0, _1) -> {
// Or used to copy the first element into a new
// BitSet.
// No need to copy here if you don't mind
// modifying the above Lists.
final BitSet tmp = BitSet.valueOf(new long[] {});
tmp.or(_0);
tmp.and(_1);
return tmp;
}))
.collect(Collectors.toList());
results.forEach(bs -> System.out.println(convert(bs)));
}
public static long convert(final BitSet bits) {
long value = 0L;
for (int i = bits.nextSetBit(0); i >= 0; i = bits.nextSetBit(i + 1)) {
value += bits.get(i) ? (1L << i) : 0L;
}
return value;
}
采用 convert
方法并从 this answer 稍作修改。
我正在尝试开发一种在多个 BigInteger 值之间执行逻辑 AND 运算的有效方法。例如,让我们考虑下面的片段:
public static void main(String[] args) {
List<BigInteger> a = Arrays.asList(new BigInteger("1000",2), new BigInteger("101",2), new BigInteger("111",2));
List<BigInteger> b = Arrays.asList(new BigInteger("10",2), new BigInteger("10110",2), new BigInteger("10011",2));
List<BigInteger> c = Arrays.asList(new BigInteger("1",2), new BigInteger("10110",2), new BigInteger("11110",2));
List<BigInteger> dd = IntStream.range(0, a.size())
.mapToObj(i -> a.get(i).and(b.get(i)).and(c.get(i)))
.collect(Collectors.toList());
System.out.println(dd);
//OUTPUT = [0, 4, 2]
}
但是,此解决方案的问题是 map 函数接受的值的静态数量。让我们假设一个包含多个列表(也超过 3 个)的 ArrayList,我该如何更改之前的解决方案?
public static void main(String[] args) {
List<BigInteger> a = Arrays.asList(new BigInteger("1000",2), new BigInteger("101",2), new BigInteger("111",2));
List<BigInteger> b = Arrays.asList(new BigInteger("10",2), new BigInteger("10110",2), new BigInteger("10011",2));
List<BigInteger> c = Arrays.asList(new BigInteger("1",2), new BigInteger("10110",2), new BigInteger("11110",2));
ArrayList<List<BigInteger>> collection = new ArrayList<List<BigInteger>>();
collection.add(a);
collection.add(b);
collection.add(c);
List<BigInteger> dd = null;
//......
System.out.println(dd);
}
请注意,我决定选择采用 stream.map(),因为列表中 BigInteger 值的数量可能很大(数千个值),我想利用 parallelStream() 来执行此操作。但是,我接受任何有效执行此操作的建议。
如果我正确理解了您的尝试,那么这就是 Stream
的 reduce
方法的用途。
例如,以下应该有效:
final List<BigInteger> result = IntStream.range(0, a.size())
.mapToObj(i -> collection.stream()
.map(l -> l.get(i)) // Map to the i'th element of all streams.
// This line is the trick. It effectively performs '&' on all elements
// in the mapped stream. The first argument is the 'identity' element
// of '&'-ing, which is a binary 11111...
// -1 Behaves like this (although I have no idea how it works for
// BigInteger, it seems to give the right values for the things you've
// given as examples).
.reduce(BigInteger.ZERO.subtract(BigInteger.ONE), BigInteger::and))
.collect(Collectors.toList());
注意:如果您在这里寻求效率(这对您的用例确实很重要),那么请考虑您是否需要 BigInteger
。忽略符号(因为你正在进行按位运算)long
数组会给你 64
位,很容易 涵盖你在示例中给出的所有内容(和常见用例中的大多数数字)并且会更快。
你可以试试这样的
List<BigInteger> dd = IntStream.range(0, a.size())
.mapToObj(i ->
collection.stream()
.map(col -> col.get(i))
.reduce(BigInteger::and)
.get())
.collect(Collectors.toList());
替代答案的灵感来自 Stanislav Bashkyrtsev's comment, which uses BitSet
s。
public static void main(String[] args) {
final List<BitSet> a = Arrays.asList(
BitSet.valueOf(new long[] {0b1000L}),
BitSet.valueOf(new long[] {0b101L}),
BitSet.valueOf(new long[] {0b111L})
);
final List<BitSet> b = Arrays.asList(
BitSet.valueOf(new long[] {0b10L}),
BitSet.valueOf(new long[] {0b1_0110L}),
BitSet.valueOf(new long[] {0b1_0011L})
);
final List<BitSet> c = Arrays.asList(
BitSet.valueOf(new long[] {0b1L}),
BitSet.valueOf(new long[] {0b1_0110L}),
BitSet.valueOf(new long[] {0b1_1110L})
);
final List<List<BitSet>> bitSets = Arrays.asList(a, b, c);
final List<BitSet> results = IntStream.range(0, a.size())
.mapToObj(i -> bitSets.stream().map(l -> l.get(i))
// First argument of reduce is identity element, it needs
// to be a BitSet with at least as many bits as any input
// ones which are all set. In this case, 64 bits are
// used, initialised by a long. If you have /more/ bits
// needed, then create one with new BitSet(bitCount);
// and then set all bits.
.reduce(BitSet.valueOf(new long[] {0xFFFF_FFFF_FFFF_FFFFL}), (_0, _1) -> {
// Or used to copy the first element into a new
// BitSet.
// No need to copy here if you don't mind
// modifying the above Lists.
final BitSet tmp = BitSet.valueOf(new long[] {});
tmp.or(_0);
tmp.and(_1);
return tmp;
}))
.collect(Collectors.toList());
results.forEach(bs -> System.out.println(convert(bs)));
}
public static long convert(final BitSet bits) {
long value = 0L;
for (int i = bits.nextSetBit(0); i >= 0; i = bits.nextSetBit(i + 1)) {
value += bits.get(i) ? (1L << i) : 0L;
}
return value;
}
采用 convert
方法并从 this answer 稍作修改。