Converting BitArray to Byte - c#

I have a code that converts BitArray values to byte[] values. I got the code also from stackoverflow.
The code is working great, I just don't understand one part.
When the codes copies the BitArray to Byte using BitArray.CopyTo() the byte reading is in LSB order.
Can someone help me understand why the converted byte is in LSB order?
strBit (is a string value that consists of 1/0)
byte[] myByte = new byte[50];
List<string> list = Enumerable.Range(0, strBit.Length / 8)
.Select(i => strBit.Substring(i * 8, 8))
.ToList();
for (int x = 0; x < list.Count; x++)
{
BitArray myBitArray = new BitArray(list[x].ToString().Select(c => c == '1').ToArray());
myBitArray.CopyTo(myByte, x);
}
Example Output:
strBit[0] = 10001111 (BitArray)
when converted to Byte:
myByte[0] = 11110001 (Byte) (241/F1)

Because we count bits from the right and items from the left; for instance for
BitArray myBitArray = new BitArray(new byte[] { 10 });
We have for the byte 10 (counting from the right):
10 = 00001010 (binary)
^
second bit (which is 1)
when items of the corresponding array we count from the left:
{false, true, false, true, false, false, false, false}
^
corresponding second BitArray item (which is true)
That's why if we want to have an array of byte back we have to Reverse each byte representation, e.g. Linq solution
using System.Collections;
using System.Linq;
...
BitArray myBitArray = ...
byte[] myByte = myBitArray
.OfType<bool>()
.Select((value, index) => new { // into chunks of size 8
value,
chunk = index / 8 })
.GroupBy(item => item.chunk, item => item.value)
.Select(chunk => chunk // Each byte representation
.Reverse() // should be reversed
.Aggregate(0, (s, bit) => (s << 1) | (bit ? 1 : 0)))
.Select(item => (byte) item)
.ToArray();

Related

How to build byte array from bytes and nibbles in C#

Given this structure of a string array
string[] content = {"0x1", "5", "0x8", "7", "0x66"};
How to get the content equivalent byte array representation? I know how to convert the "5", "7" and "0x66" but I'm struggling to build the whole byte array representation of the nibbles 0x1, 0x8 in the array... Basically I don't know how to concat the "0x1", "5", "0x8" to two bytes...
Additional Info: The sequence of the string array contains only byte or nibble data. Prefixed "0x" and one digit is to be intepreted as a nibble, digits without prefix should be intepreted as byte, hex strings with two numbers should be intepreted as byte.
If all items are supposed to be hexadecimal, Linq and Convert are enough:
string[] content = {"0x1", "5", "0x8", "7", "0x66"};
byte[] result = content
.Select(item => Convert.ToByte(item, 16))
.ToArray();
If "5" and "7" are supposed to be decimal (since they don't start from 0x) we have to add a condition:
byte[] result = content
.Select(item => Convert.ToByte(item, item.StartsWith("0x", StringComparison.OrdinalIgnoreCase)
? 16
: 10))
.ToArray();
Edit: If we want to combine nibbles, let's extract a method for it:
private static byte[] Nibbles(IEnumerable<string> data) {
List<byte> list = new List<byte>();
bool head = true;
foreach (var item in data) {
byte value = item.StartsWith("0x", StringComparison.OrdinalIgnoreCase)
? Convert.ToByte(item, 16)
: Convert.ToByte(item, 10);
// Do we have a nibble?
// 0xDigit (Length = 3) or Digit (Length = 1) are supposed to be nibble
if (item.Length == 3 || item.Length == 1) { // Nibble
if (head) // Head
list.Add(Convert.ToByte(item, 16));
else // Tail
list[list.Count - 1] = (byte)(list[list.Count - 1] * 16 + value);
head = !head;
}
else { // Entire byte
head = true;
list.Add(value);
}
}
return list.ToArray();
}
...
string[] content = { "0x1", "5", "0x8", "7", "0x66" };
Console.Write(string.Join(", ", Nibbles(content)
.Select(item => $"0x{item:x2}").ToArray()));
Outcome:
// "0x1", "5" are combined into 0x15
// "0x8", "7" are combined into 0x87
// "0x66" is treated as a byte 0x66
0x15, 0x87, 0x66
You can use the Zip method, to combine the source with the same source offset by 1.
string[] source = { "0x1", "5", "0x8", "7", "0x66" };
var offsetSource = source.Skip(1).Concat(new string[] { "" });
var bytes = source
.Zip(offsetSource, (s1, s2) => s1 + s2)
.Where(s => s.Length == 4 && s.StartsWith("0x"))
.Select(s => Convert.ToByte(s, 16))
.ToArray();
Console.WriteLine(String.Join(", ", bytes)); // Output: 21, 135, 102

Convert binary data to 2’s complement and then place in output array

Scenario:
I have binary data. My requirement is that I need an output array of bytes contain in following order:
Sequentially read each 2 bytes
and then convert into 2’s complement
and then placed into output array.
Please help me.
Providing, that the binary data in the question is in fact an array:
Byte[] binaryData = new Byte[] {
0x12, 0x13, 0x14, 0x15
};
Byte[] result = Enumerable
.Range(0, binaryData.Length / 2)
.Select(index => unchecked(BitConverter.ToInt16(binaryData, index * 2)))
//.Select(item => (Int16) unchecked((item << 8) | (item >> 8))) // if you want to swap the endians
.Select(value => (Int16) unchecked(~value + 1))
.SelectMany(value => unchecked(new Byte[] {(Byte) (value >> 8), (Byte) (value & 0xFF)}))
.ToArray();
// Test
// "ec, ee, ea, ec"
// ("ed, ed, eb, eb" when endians are swapped)
Console.Write(String.Join(", ", result.Select(item => item.ToString("x2"))));
Edit: in case (see comments) that each byte (not 2-byte word) should be changed:
Byte[] binaryData = new Byte[] {
224, 46
};
Byte[] result = binaryData
.Select(b => unchecked((Byte) (~b + 1)))
.ToArray();
// "20 D2"
Console.Write(String.Join(", ", result.Select(item => item.ToString("x2"))));

How to sort a List of integer arrays of varying size?

I've done some extensive searching for this so if this is a duplicate please slaughter me :D
I have a List of byte arrays (List) where the arrays are of varying length. I need to sort the list by the array lengths in ascending order then by the bytes in the array (please see example).
Example:
I want to go from:
{0,1,2}
{0,4}
{0,3,2}
{0,1,3}
{0,2,4,6,1}
{0,1,1}
{0,3,4,5}
to:
{0,4}
{0,1,1}
{0,1,2}
{0,1,3}
{0,3,2}
{0,3,4,5}
{0,2,4,6,1}
It's essentially alphabetical order but with a set of numbers instead of characters (arguably the same thing), any ideas?
The only thing you need to do is implement a IComparer<T> interface and provide that to the sorting algorithm. In this case the algorithm looks like:
public ByteArrayComparer : IComparer<byte[]> {
public int Compare (byte[] ba, byte[] bb) {
int n = ba.Length; //fetch the length of the first array
int ci = n.CompareTo(bb.Length); //compare to the second
if(ci != 0) { //if not equal return the compare result
return ci;
} else { //else elementwise comparer
for(int i = 0; i < n; i++) {
if(ba[i] != bb[i]) { //if not equal element, return compare result
return ba[i].CompareTo(bb[i]);
}
}
return 0; //if all equal, return 0
}
}
}
Next you can use the List<T>.Sort method:
List<byte[]> data = new List<byte[]>();
//add arrays to data
data.Sort(new ByteArrayComparer());
//data is now sorted
The sorting algorithm requires that the comparator is valid, a comparator is valid if it satisfies the three constraints on an ordering relation:
Reflexivity: if an elements is compared with itself, return 0;
Anti-symmetric: If x is smaller than y (return something less than 0), then y is greater than x (something greater than 0);
Transitive: if x is smaller than y and y is smaller than z, then x is smaller than z.
If the comparer doesn't satisfy that relation, the sorting algorithm will fail to sort correctly, simply because your order makes no sense.
Why not simply use LINQ
MyList = MyList.OrderBy(arr=>arr.Length).ThenBy(arr =>arr.Sum()).ToList();
A working example :
List<int[]> a = new List<int[]>();
int[] t1 = { 0, 4 };
int[] t2 = { 0, 1, 2 };
int[] t3 = { 0, 1, 3 };
int[] t4 = { 0, 2, 4, 6, 1 };
int[] t5 = { 0, 1, 1 };
int[] t6 = { 0, 3, 4, 5 };
a.Add(t1);
a.Add(t2);
a.Add(t3);
a.Add(t4);
a.Add(t5);
a.Add(t6);
a = a.OrderBy(arr=>arr.Length).ThenBy(arr =>arr.Sum()).ToList();
foreach (int[] item in a)
{
foreach (int item2 in item)
{
Console.Write(" "+item2);
}
Console.WriteLine();
}
Sample output :
0 4
0 1
0 1 2
0 1 3
0 3 4 5
0 2 4 6 1
And as pointed out this could fail in scenarios like {3 4 5} , {4 5 3}

Get an array of bits that represent an int in c#

Is there a way to show the representation of an int in bits in c#?
i.e.
1 = 00001
20 = 10100
etc.
I have tried using BitConverter with no luck. This should be simple, but I can't find a solution!
Convert.ToString(value, base)
Converts the value of a 32-bit signed integer to its equivalent string representation in a specified base. Specify 2 for the base.
Here's a one-liner using linq:
var myint = 20;
var bytes = Enumerable.Range(0, 32).Select(b => (myint >> b) & 1);
// { 0, 0, 1, 0, 1, 0 ... }
Of course this is in reverse order, to swap it around just use:
var myint = 20;
var bytes = Enumerable.Range(0, 32).Select(b => (myint >> (31 - b)) & 1);
// { ..., 0, 1, 0, 1, 0, 0 }
You could also look at using a BitArray.
var array = new BitArray(BitConverter.GetBytes(1));

Sort an integer array by given starting integer

I have an array:
int[] months = new int[4] {1, 4, 7, 10};
I would like to sort the array starting by the given value and sort the rest of the array in the original order.
Let's say I want to start sorting the array by a value of 7. The sorted array would be then in order of:
7, 10, 1, 4
Or starting with a value 4 the sorted array would be an order of
4, 7, 10, 1
How about:
var orderedMonths = months.Where(x => x >= 7)
.OrderBy(x => x)
.Concat(months.Where(x => x < 7));
Note that this will mean that the elements of the "rest of the array" will be in order of appearance rather than increasing numeric order. If you meant the latter (i.e. sort both 'segments' numerically) , I would do:
var orderedMonths = months.OrderBy(x => x < 7) // false comes before true
.ThenBy(x => x);
On the other hand, if you want to sort both segments by order of appearance, I would do:
var orderedMonths = months.GroupBy(x => x < 7)
.OrderBy(group => group)
.SelectMany(x => x);
(or)
var orderedMonths = months.Where(x => x >= 7)
.Concat(months.Where(x => x < 7));
Assuming this is your sorted int array you could
int[] months = new int[4] { 1, 4, 7, 10 };
int value = 10;
int[] chk1 = new int[4];
chk1 = months.SkipWhile(a => a != value).
Concat(months.TakeWhile(a => a != value)).ToArray();
This should get you the required order
Can you use a list?
int NumberToBeFound = 7;
int IndexOfNumber = -1;
for(int i=0;i<months.count;i++){
if(months[i] == NumberToBeFound){
IndexOfNumber = i;
break;
}
}
List<int> Sorted = new List<int>();
for(int i = IndexOfNumber; i < months.count;i++){
Sorted.Add(months[i]);
}
for(int i = 0; i < IndexOfNumber; i++){
Sorted.Add(months[i]);
}
months = Sorted.ToArray();

Categories

Resources