I have an array of 8 booleans which I want to simply convert to a byte. Is there a simple way to do this? Or do I have to use for loop?
Personally I'd prefer a simple up to two lines solution if it exists.
Thanks for help.
EDIT: Possible duplicate is just one boolean to a byte, I have an array.
ANOTHER EDIT: I get a byte from a udp packet then I set the first bit (boolean) to false, then I would need to get a byte out of that again.
I think a loop is better, but if you must have a one liner :
byte b = (byte)((bool[0]?1<<7:0) + (bool[1]?1<<6:0) + (bool[2]?1<<5:0) +
(bool[3]?1<<4:0) + (bool[4]?1<<3:0) + (bool[5]?1<<2:0) +
(bool[6]?1<<1:0) + (bool[7]?1:0));
For the input :
boolean[] bool = new boolean[] {false,false,true,false,true,false,true,false};
you get the byte 42.
if i understood your question correct, then you want to convert a byte that is represented by it's bit pattern as an array of booleans ...
if that is the case then this is one solution :
public static void main(String[] args) {
// The integer where the result will be build up
int result = 0;
// The bit-pattern as an array of booleans
// 2^0 Position is at bools[0] !!
// so this is the byte '0 1 0 1 0 1 0 1' --> decimal : 85
boolean[] bools = new boolean[]{ true, false, true, false, true, false, true, false };
// iterate through the 'bits'
// and set the corresponding position in the result to '1' if the 'bit' is set
for (int i = 0; i < bools.length; i++) {
if (bools[i]) {
result |= 1 << i;
}
}
System.out.println(result); // Prints '85'
}
I'd do it like this:
byte b = 0;
for(int i=0;i<8;i++) if(binaryValues[i]) b |= (128 >> i);
return b;
Related
I input a series of numbers like 1 2 3 4, which i can either add or subtract to each other and then I specify it must equal 4. I use a Boolean array to represent the two operations: True = '+' and False = '-'. I use a method call in a while loop that will generate every possible combination of true or false in the Boolean array. My code does generate combinations to solve the series of numbers, but when the number series are 15 or greater the method takes far too long and will not solve the series of numbers.
Does anyone have a suggestion on how i could make this more efficient and be able to solve number series with more than 20 Ints?
private static boolean hasNextOper(boolean[] oper) {
for (int i = 0; i < oper.length; i++) {
if (oper[i]) {
oper[i] = false;
} else {
oper[i] = true;
return true;
}
}
return false;
}
This method is also being called like this:
while (hasNextOper(oper)) {
if (isTarget(oper, numbers, target, order)) {
displayResults(oper, numbers, target, order);
return;
}
}
Your hasNextOper method seems to be cycling through these array values:
{false, false, true }
{false, true , false}
{false, true , true }
{true , false, false}
...
Note how these change in the same pattern as a binary number: 000, 001, 010, .... Therefore you should be able to take an integer (a long type gives you up to 64 bits; if you want more, use a BigInteger but that's a bit more complicated).
// Example: generate all possible combinations in an array of 20 booleans.
final int length = 20;
for (long n = 0; n < (1 << length); n++) {
oper = longBitsToBoolArray(n, length);
// ... now do things with oper
// ...
}
static bool[] longBitsToBoolArray(long bits, int length) {
bool[] oper = new bool[length];
for (int i = 0; i < length; i++)
oper[i] = ((bits >>> i) & 1) != 0;
}
I am using BitSet to represent possible hours where lectures are filled in, the case is that when you put to false the corner bits, they are simplified, this means that they are not anymore in the BitSet. How can I ask BitSet to not simplify?
To make my explanation clearer this is the code:
for(Map.Entry<GrupAssig, BitSet> entry : bitsetPerGrup.entrySet()){
BitSet bitset = entry.getValue();
//n franges per dia
int numFranges = UnitatDocent.getNumFranges();
int indexDia = this.dia.id() * numFranges;
bitset.clear(indexDia, indexDia+numFranges);
}
Imagine that the bitset has 60 bits by default, and numFranges=12 and this.dia.id()=4. This would make the last twelve bits set to 0. The result I get is:
111111111111111111111111111111111111111111111111
But if this.dia.id()=3 I get:
11111111111111111111111111111111111100000000000011111111111
And you can print the BitSet this way:
public static void printBitset(BitSet b) {
StringBuilder s = new StringBuilder();
for( int i = 0; i < b.length(); i++ )
{
s.append( b.get( i ) == true ? 1 : 0 );
}
System.out.println( s );
}
Which demonstrates what I am saying.
Thank you.
Here's the documentation for BitSet.length:
length()
Returns the "logical size" of this BitSet: the index of the highest set bit in the BitSet plus one.
If you need to print out a certain number of bits (e.g. 60) then use a constant instead of ".length()" for your loop. You can call ".get(index)" on any index regardless of the length and it will give you the result for that bit.
For instance the following code produces "0000011000":
import java.util.BitSet;
public class Main {
public static void main(String[] args) {
BitSet bits = new BitSet();
bits.set(5);
bits.set(6);
StringBuilder bitString = new StringBuilder();
for (int i = 0; i < 10; i++) {
bitString.append(bits.get(i) ? "1" : "0");
}
System.out.println(bitString.toString());
}
}
I am looking for an efficient way how to easily convert a BitSet to a binary string. Let us say that its usual length would be thousands of bits.
For example, lets have this:
BitSet bits = new BitSet(8);
bits.set(1);
bits.set(3);
And this is the desired result:
String result = toBinaryString(bits);
// expected: result = "01010000"
I have some ideas in general (streams, etc.), but there might be some obvious standard method I am just missing.
So this is the most efficient way I have tried so far:
private static class FixedSizeBitSet extends BitSet {
private final int nbits;
public FixedSizeBitSet(final int nbits) {
super(nbits);
this.nbits = nbits;
}
#Override
public String toString() {
final StringBuilder buffer = new StringBuilder(nbits);
IntStream.range(0, nbits).mapToObj(i -> get(i) ? '1' : '0').forEach(buffer::append);
return buffer.toString();
}
}
Or other way using more streams:
#Override
public String toString() {
return IntStream
.range(0, nbits)
.mapToObj(i -> get(i) ? '1' : '0')
.collect(
() -> new StringBuilder(nbits),
(buffer, characterToAdd) -> buffer.append(characterToAdd),
StringBuilder::append
)
.toString();
}
String bitsStr = String.format("%8s", Integer.toBinaryString(bits.toByteArray()[0] & 0xFF)).replace(' ', '0');
Update:
It turns out that the real culprit here is BitSet.valueOf which doesn't work the way you would expect it to work. I'm going to leave my original comment here because it could be valuable to someone.
The important things to know are that if you call BitSet.valueOf(some byte array) it's not going to do what you think it should do and that you can't rely on BitSet.toByteArray() either.
import java.util.Arrays;
import java.util.BitSet;
public class MoreBitSetExperiments {
public static void main(String[] args) {
// create 10000000 00000001 00000000 as bit set using set() method
int bits = 24;
BitSet bitSet1 = new BitSet(bits);
bitSet1.set(0);
bitSet1.set(15);
// create 10000000 00000001 00000000 as bit set using valueOf() method
BitSet bitSet2 = BitSet.valueOf(new byte[] {(byte)0b10000000, (byte)0b0000001, (byte)0b00000000});
System.out.println("bitSet1.toByteArray(): " + Arrays.toString(bitSet1.toByteArray()));
System.out.println("bitSet2.toByteArray(): " + Arrays.toString(bitSet2.toByteArray()));
String binary1 = "";
String binary2 = "";
for (int i = 0; i < bits; i++) {
binary1 = binary1 + (bitSet1.get(i) ? 1 : 0);
binary2 = binary2 + (bitSet2.get(i) ? 1 : 0);
}
System.out.println("bitSet1 binary: " + binary1);
System.out.println("bitSet2 binary: " + binary2);
}
}
Output:
bitSet1.toByteArray(): [1, -128]
bitSet2.toByteArray(): [-128, 1]
bitSet1 binary: 100000000000000100000000
bitSet2 binary: 000000011000000000000000
To get back to the original question, as long as you create your bit set by calling the BitSet.set() method you can get a binary string with bits in the order you expect. But if you create your bit set using BitSet.valueOf() then your bytes will be backwards. Also, since you can't know how many 0 bytes should be at the end of your bit set, any code written to convert to binary needs to know the intended length in bytes of the output.
Original Post
I've spent the last several days debugging some issues related to bitsets so I thought I'd share.
This code demonstrates that there are 3 big unexpected behaviors with bit sets. This is because the bit set internal storage mechanism is not what you expect it to be at first glance:
import java.util.Arrays;
import java.util.BitSet;
public class BitSetExperiments {
// this class seeks to demonstrate some of the pitfalls of using the BitSet object
public static void main(String[] args) {
byte[] bytes = new byte[] {-128, 1, 0}; // 10000000 00000001 00000000 as binary
BitSet bitSet = BitSet.valueOf(bytes);
// unexpected behavior demonstrated here
System.out.println("problem 1: BitSet.toByteArray() produces unexpected results (trailing 0 bytes are not captured):");
System.out.println(" expected byte array : [-128, 1, 0]");
System.out.println("actual bitset.toByteArray(): " + Arrays.toString(bitSet.toByteArray()));
System.out.println();
System.out.println("problem 2: BitSet stores the bits of a byte in the wrong order:");
System.out.println("expected binary: 100000000000000100000000");
System.out.print("actual binary: ");
for (int i = 0; i < bytes.length * 8; i++) {
System.out.print(bitSet.get(i) ? 1 : 0);
}
System.out.println("\n");
System.out.println("problem 3: bitSet cannot accurately tell you the length of bytes or bits stored");
System.out.println("expected bit/byte length is: 24 bits or 3 bytes");
System.out.println("bitSet.size(): " + bitSet.size());
System.out.println("bitSet.length(): " + bitSet.length());
System.out.println("bitSet.cardinality(): " + bitSet.cardinality());
System.out.println();
}
}
Running this code shows:
problem 1: BitSet.toByteArray() produces unexpected results (trailing 0 bytes are not captured):
expected byte array : [-128, 1, 0]
actual bitset.toByteArray(): [-128, 1]
problem 2: BitSet stores the bits of a byte in the wrong order:
expected binary: 100000000000000100000000
actual binary: 000000011000000000000000
problem 3: bitSet cannot accurately tell you the length of bytes or bits stored
expected bit/byte length is: 24 bits or 3 bytes
bitSet.size(): 64
bitSet.length(): 9
bitSet.cardinality(): 2
Ok, so knowing these 3 unexpected behaviors, we can code around them. But the important thing to realize is that you don't know how many trailing 0 bytes are on your bit set, and bit set won't tell you. This means when you want to convert the bit set to binary, you need to be explicit about how many bytes you're expecting.
Here's what I came up with:
public static String convertBitSetToBinaryString(BitSet bitSet, int lengthInBytes) {
if(bitSet == null) {
return null;
}
if(lengthInBytes < 0) {
return "";
}
StringBuilder binary = new StringBuilder();
// compute each byte, and then reverse them before appending to the running binary
for(int i = 0; i < lengthInBytes; i++) {
StringBuilder backwardsByte = new StringBuilder();
for(int j = 0; j < Byte.SIZE; j++) {
backwardsByte.append(bitSet.get((i*Byte.SIZE)+j) ? "1" : "0");
}
binary.append(StringUtils.reverse(backwardsByte.toString()));
}
return binary.toString();
}
note: uses StringUtils.reverse() from apache commons
And here is the test to make sure it actually works:
void testConvertBitSetToBinaryString() {
assertNull(convertBitSetToBinaryString(null, 0));
assertNull(convertBitSetToBinaryString(null, 1));
assertEquals("00000000", convertBitSetToBinaryString(BitSet.valueOf(new byte[] {}), 1));
assertEquals("00000000", convertBitSetToBinaryString(BitSet.valueOf(new byte[] {0}), 1));
assertEquals("10000000", convertBitSetToBinaryString(BitSet.valueOf(new byte[] {-128}), 1));
assertEquals("00000001", convertBitSetToBinaryString(BitSet.valueOf(new byte[] {1}), 1));
assertEquals("0000000100000000", convertBitSetToBinaryString(BitSet.valueOf(new byte[] {1}), 2));
assertEquals("0000000100000010", convertBitSetToBinaryString(BitSet.valueOf(new byte[] {1, 2}), 2));
assertEquals("1000000010000000", convertBitSetToBinaryString(BitSet.valueOf(new byte[] {-128, -128}), 2));
assertEquals(
"00000001 01001101 10000000 00000000".replace(" ", ""),
convertBitSetToBinaryStringV2(BitSet.valueOf(new byte[] {1, 77, -128, 0}), 4)
);
}
I need help sorting an integer array using selection sort. It won't sort for some reaons. Below is my demo/main.
02
20
01
it should be
01
02
20
My demo/main:
public static void main(String[] args) {
SelectionSortArray[] ints = new SelectionSortArray[3];
ints [0] = new SelectionSortArray(02);
ints [1] = new SelectionSortArray(20);
ints [2] = new SelectionSortArray(01);
System.out.println("Unsorted array: ");
for (int index = 0; index < ints.length; index++) {
System.out.println(ints[index]);
}
SelectionSort.selectionSort(ints);
System.out.println(" ");
System.out.println("Sorted array using selection sort: ");
for (int index = 0; index < ints.length; index++) {
System.out.println(ints[index]);
}
}
Your compareTo method in the SelectionSortArray class is incorrect. The compareTo method must return an int less than zero if the current object is less than the other object, yet you have it returning 1.
Quoting from the linked Javadocs:
Compares this object with the specified object for order. Returns a
negative integer, zero, or a positive integer as this object is less
than, equal to, or greater than the specified object.
Try these changes:
if (num == other.num) {
result = 0; // This was correct; no change here.
} else if (num < other.num) {
result = -1; // Changed from 1 to -1.
} else {
result = 1; // 1 or 2 is fine, as long as it's positive
}
Your CompareTo function is wrong. Just change it to:
public int compareTo(SelectionSortArray other) {
return num.compareTo(other.num);
}
The key is the -1 / 0 / 1 return codes, rather than the "0,1,2" that you're using.
Generally if you're comparing built in types, it's easier to just delegate to the built in comparison operators.
Note: To use "num.compareTo" you need to use "Integer" rather than "int". If you want to stick with "int", you need the solution posted by rgettman.
Note that along with the changes to compareTo,
return Integer.compare(this.num,other.num)
Which is implemented to return what you are returning but in a concise way
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
if you want to see the printed output in the way you listed in your question use
System.out.format("%02d%n",ints[index].num);
or alter toString() to return String.format("%02d",num)
You might also want to see java.util.Arrays source code so see how few other similar methods have been implemented. Also consider changing your class name to indicate that it holds number CustomNumber and encapsulate your class to avoid direct access to num.
And another Interesting catch in your code
SelectionSortArray[] ints = new SelectionSortArray[8];
ints[0] = new SelectionSortArray(01);
ints[1] = new SelectionSortArray(02);
ints[3] = new SelectionSortArray(03);
ints[4] = new SelectionSortArray(04);
ints[5] = new SelectionSortArray(05);
ints[6] = new SelectionSortArray(06);
ints[7] = new SelectionSortArray(07);
ints[8] = new SelectionSortArray(08);//???
if you precede a number with 0 it will be an Octal number and allowed digits are 0 - 7 hence you will see compilation error above. Also
System.out.println(0123);
System.out.println(0234);
will not print
0123
0234
as you (un)expected !
83
156
Just be cautious while using octal numbers in your code.
The following is the problem I'm working on and my snippet of code.
Is there a better way to implement this? I have used basic control structures for this below.
Is it better to store the rows and columns in a map and searching through the map based on the key/value pairs?
There is a security keypad at the entrance of a building. It has 9 numbers 1 - 9 in a 3x3 matrix format.
1 2 3
4 5 6
7 8 9
The security has decided to allow one digit error for a person but that digit should be horizontal or vertical. Example: for 5 the user is allowed to enter 2, 4, 6, 8 or for 4 the user is allowed to enter 1, 5, 7. IF the security code to enter is 1478 and if the user enters 1178 he should be allowed.
The following is a snippet of code i was working on:
ArrayList<Integer> list = new ArrayList<Integer>();
int num = 9;
int[][] arr = {{1,2,3},{4,5,6},{7,8,9}};
for(int i =0;i< arr.length;i++){
for(int j = 0; j <arr.length;j++){
if(num == arr[i][j]){
row = i;
col = j;
break;
}
}
}
for(int j1 = 0; j1< 3 ; j1++){
if(arr[row][j1] != num){
list.add(arr[row][j1]);
}
}
for(int i1 = 0 ; i1 <3;i1++){
if(arr[i1][col] != num){
list.add(arr[i1][col]);
}
}
There are many ways to solve this, but I think it can be solved with HashMaps and HashSets more efficiently than doing several iterations.
If I were you, I would build the data model first using a hash map and a hash set. This is because hash map and hash set have fast lookup, (no iterations)
HashMap<Integer,HashSet<Integer>> values = new HashMap<Integer, HashSet<Integer>>();
//now put in the accepted values for one
HashSet<Integer> oneValues = new HashSet<Integer>();
oneValues.put(1);
oneValues.put(2);
oneValues.put(4);
values.put(1, oneValues);
//put in 2 values
......
Then when you parse your input, if you want to see if an inputed value is accepted for what the code is, just do something like
private boolean isAccepted(int input, int combinationValue)
{
// check to see if the inputed value in the accepted values set
return values.get(combinationValue).contains(input);
}
I would tend to want a function along the lines of isCloseTo(int a, int b) So, say, if I called isCloseTo(5, 5) it would return true. If I called isCloseTo(2, 5) it should return true, too. But if I called isCloseTo(1, 3) it would return false.
So I'd write tests like that:
assertTrue(isCloseTo(5, 5));
OK, that's really easy to get to pass:
public boolean isCloseTo(int a, int b) {return true;}
Then, maybe
assertFalse(isCloseTo(1, 3));
which fails with the above implementation, so I'd need to change it
public boolean isCloseTo(int a, int b) {return a == b;}
That's still an incomplete implementation, so we need another test
assertTrue(isCloseTo(1, 2));
Now we start to need some real substance. And I think I'll leave the rest as an exercise for the reader. Yes, I've left the tricky bits out, but this is a strategy (test-driven design) that leads you more directly to solutions than just trying to write the code. As long as you keep all the test passing, you make steady progress toward a complete solution. Good luck!
There are many different acceptable solutions here. I suppose it's easier to construct 10x10 matrix of integer to check for the errors (for example errorMatrix). First index then will mean original digit, second index - digit typed by user, and value of arr[i][j] is a number of errors for this digit pair. Initialize it that way:
errorMatrix[i][i] = 0 //no error
errorMatrix[i][j] = 1, where i and j are horizontally or vertically neighboring digits
errorMatrix[i][j] = 2, in other cases.
Then for every digit pair you will get number of errors in O(1). You stated that you will accept only one error, so the value of 2 for unmatched pairs will be enough and you can just sum up the error numbers and compare it to one.
So, how to construct this. Iterate through all of the digit pairs and find the value of error. You should better implement function CheckError that will calculate it for digit pair a and b
if a=b, then errorMatrix is 0;
The digits a and b are vertical
neighbors if abs(a-b) = 3. So, is
abs(a-b)==3 set errorMatrix[a][b] =
1;
The digits a and b are horizontal
neighbors if
a. (a-1)/3==(b-1)/3 - here we check that this digits are on the same line.
b. abs(a-b)==1 - here we check that digits are in the neighboring cells.
If (a) and (b) then error value is 1;
In other cases error value is 2.
It seems to me that this spec is right. However, you need to test it before using
So, if you then want to handle the changes of the keypad layout you just have to rewrite CheckError method.
Hope it helps.
Or this...
boolean matchDigit(int p, int d) {
return (p==d)
|| (p==d-3)
|| (p==d+3)
|| (d%3!=1 && p==d-1)
|| (d%3!=0 && p==d+1);
}
this assumes we've already assured that p and d are between 1 and 9.
For the specific keyboard in your question we can use a base 3 to solve this problem and to calculate the distances between digits/keys.
1 { 1 / 3, 1 % 3 } = {0, 1}
2 { 2 / 3, 2 % 3 } = {0, 2}
...
5 { 5 / 3, 5 % 3 } = {1, 2}
...
8 { 8 / 3, 8 % 3 } = {2, 2}
public boolean isValidCode(int code, int expexted) {
while(code > 0)
{
if (!isValidDigit(code % 10, expected % 10))
return false ;
code /= 10 ;
expected /= 10 ;
}
return (code == expected) ;
}
public boolean isValidDigit(int a, int b) {
int dx = (a - b) / 3 ;
int dy = (a - b) % 3 ;
return ((Math.abs(dx) + Math.abs(dy)) == 1)
}
A more generic and robust solution will be to create a Map where you can set what other keys you accept.
Sample: allowing A, Z, P, M, N for A: place a new entry 'A'="AZPMN" in the map, validation checkd if the character is the same or if the type character is in the exceptions string.
private Map acceptedChars = new HashMap() ;
public void loadAcceptedCharacters() {
acceptedChars.put('A', "AZPMN") ;
}
public boolean isValidKeyword(String word, String expected)
{
if (word == null || word.matches("\\s*"))
return false ;
if (word.length() != expected.length())
return false ;
for(int idx = 0; idx < word.length(); idx++)
{
if (!isValidDigit(word.chatAt(idx), expected.charAt(idx)))
return false ;
}
return true ;
}
public boolean isValidDigit(char chr, char expected) {
String accepted ;
if (chr != expected)
{
accepted = acceptedChars.get(chr) ;
if (accepted == null)
return false ;
if (accepted.indexOf(chr) < 0)
return false ;
}
return true ;
}