1

I have the following two-dimensional int array:

int[][] array = new int[128][128];

This two-dimensional array contains only zeros and ones. I want to read each line and make a byte[] (byte array) out of its contents. For instance, let's say that the first line is: 0101111000111...101, consisting of 128 numbers. I want this line to be a byte[] of 128 bits (which means 16 bytes).

What's the most efficient way to transform each line into a byte array? Bear in mind that maintaining the size is important. Since each lines consists of 128 "bits" the byte array should have a size of 16 bytes (128/8).

One way I've thought on how to do this is to make each line into a BigInteger and then convert it into byte array but unfortunately I can't produce the proper results. I've also tried some of the other options available to StackOverflow to no avail. For instance this solution produces an output of 512 and I don't understand why.

For the above reason I don't consider this post a duplicate since the various asks and answers don't take in mind the size of the byte array and its correlation to the int array.

Community
  • 1
  • 1
Aventinus
  • 1,322
  • 2
  • 15
  • 33
  • As for your example-solution: 512 = 128 * 4 and `int` is 4 bytes long. That solution simply gets all bytes from an `int`. You want another kind of transformation, so you'll have to use another approach. –  Feb 11 '16 at 17:21
  • Can you guarantee that your first array will always be a multiple of 8? – Andrew Williamson Feb 11 '16 at 17:23
  • @Paul Makes sense now that you mention it. – Aventinus Feb 11 '16 at 17:28
  • @AndrewWilliamson Indeed an important question. **Yes**, I can guarantee it. The size will always be divisible by 8. – Aventinus Feb 11 '16 at 17:28
  • 1
    So the result should be a `byte b[][] = new byte[128][16]`, right? (And not a `byte b[] = new byte[128*16]` ...) – Marco13 Feb 11 '16 at 17:29
  • @Marco13 Yes, the result is basically a byte array of byte arrays, i.e. `byte[][] b = new byte[128][]`, where each of the 128 byte arrays has a size of 16 bytes. – Aventinus Feb 11 '16 at 17:58

3 Answers3

2

Since you know that the array will always be a multiple of 8, then you can safely convert from binary to bytes with bit manipulations.

public byte getByte(int[][] array, int x, int y) {
    byte result = 0;
    for (int bit = 0; bit < 8; bit++)
        result += (byte)(array[x][y + bit] * (1 << bit));
    return result;
}

Alternatively, as @Andreas pointed out, Most Significant Bit normally comes first. Just change the for-loop to this:

result += (byte)(array[x][y + bit] * (128 >> bit));
Andrew Williamson
  • 8,299
  • 3
  • 34
  • 62
2

Here's code for a 1D array. You just repeatedly do that for the outer array of a 2D array.

int[] bits = {0,1,0,1,1,1,1,0,0,0,1,1,1,1,0,1};
assert bits.length % 8 == 0;

byte[] bytes = new byte[bits.length / 8];
for (int i = 0; i < bytes.length; i++) {
    int b = 0;
    for (int j = 0; j < 8; j++)
        b = (b << 1) + bits[i * 8 + j];
    bytes[i] = (byte)b;
}

for (int i = 0; i < bytes.length; i++)
    System.out.printf("%02x ", bytes[i]); // prints: 5e 3d 
System.out.println();

This is the more common Most Significant Bit First.
Answer by @AndrewWilliamson shows an algorithm for Least Significant Bit First.

Andreas
  • 154,647
  • 11
  • 152
  • 247
1

The approach that you linked to converts the ints to bytes by simply considering the four individual bytes that an int consists of.

What you need is a method that sets individual bits in the resulting bytes. This can be done by checking whether each of the 128 values in the input array is 0 or 1, and setting the corresponding bit in the output array acoordingly. This can be done with each row independently.

Here is an MCVE that shows the conversion process and prints and compares the results:

import java.util.Random;

public class IntArrayToByteArray2D
{
    public static void main(String[] args)
    {
        int sizeX = 128;
        int sizeY = 128;
        int input[][] = new int[sizeX][sizeY];

        Random random = new Random(0);
        for (int x=0; x<sizeX; x++)
        {
            for (int y=0; y<sizeY; y++)
            {
                boolean b = random.nextBoolean();
                input[x][y] = b ? 1 : 0;
            }
        }

        System.out.println("Input: ");
        String inputString = createString(input);
        System.out.println(inputString);

        byte output[][] = convert(input);
        String outputString = createString(output);
        System.out.println(outputString);

        System.out.println(inputString.equals(outputString));
    }

    private static byte[][] convert(int input[][])
    {
        byte output[][] = new byte[input.length][];
        for (int i=0; i<input.length; i++)
        {
            output[i] = convert(input[i]);
        }
        return output;
    }

    private static byte[] convert(int input[])
    {
        // Check whether input.length is divisible by 8, if desired
        byte output[] = new byte[input.length >> 3];
        for (int i=0; i<output.length; i++)
        {
            for (int j=0; j<8; j++)
            {
                if (input[(i<<3)+j] != 0)
                {
                    output[i] |= (1 << j); 
                }
            }
        }
        return output;
    }

    private static String createString(int array[][])
    {
        StringBuilder sb = new StringBuilder();
        for (int x=0; x<array.length; x++)
        {
            for (int y=0; y<array[x].length; y++)
            {
                sb.append(array[x][y]);
            }
            sb.append("\n");
        }
        return sb.toString();
    }

    private static String createString(byte array[][])
    {
        StringBuilder sb = new StringBuilder();
        for (int x=0; x<array.length; x++)
        {
            for (int y=0; y<array[x].length; y++)
            {
                for (int b=0; b<8; b++)
                {
                    if ((array[x][y] & (1<<b)) == 0)
                    {
                        sb.append("0");
                    }
                    else
                    {
                        sb.append("1");
                    }
                }
            }
            sb.append("\n");
        }
        return sb.toString();
    }


}
Marco13
  • 53,703
  • 9
  • 80
  • 159