How to build byte array from bytes and nibbles in C# - 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

Related

How to out all the int values from a string array and store that int values in another array

There are words and int values in a string array. My goal is to retrieve the int values from another array. I have seen two methods for converting and finding int values from a string array.
To get all the int values from the string, I first create another int array and use an Array.ConvertAll init. The second method is to loop through isDigit().
Now, the problem is that I cannot find a way to store that value in an int array that has been converted to an int. The final goal is to find the minimum and maximum value from the converted values.
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
int result;
int[] num = Array.ConvertAll(strArray1, x =>
{
bool convertStrIntoInt = int.TryParse(x, out int result);
return result;
});
In here, I don't how to get the result outside of it to do a sort to find min and max values.
I don't understand what you want but if you want only int then use this
List<int> list = new List<int>();
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
foreach (string str in strArray1)
{
if (int.TryParse(str, out int val))
{
list.Add(val);
}
}
int[] vs = list.ToArray();
now all the int values are stored in vs array, if there are some words which contains the int value and you want them to be extracted you can use regex to find the digits in word also
I'd use LINQ for this:
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
int[] num =
(
from x in strArray1
let n = int.TryParse(x, out int n) ? (int?)n : null
where n.HasValue
select n.Value
).ToArray();
That outputs:
Then you can do this:
int max = num.Max();
int min = num.Min();
Little optimized solution could be something like below
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
var numArray = strArray1.Where(var=> new Regex(#"^\d+").IsMatch(var)).ToArray();
var res = Array.ConvertAll(numArray,s => int.Parse(s));
If we don't want to use Regex can try something like below
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
int testNum;
var numArray = strArray1.Where(var=> int.TryParse(var,out testNum)).ToArray();
var res = Array.ConvertAll(numArray,s => int.Parse(s));
You can then get max and min value using
res.Min(), res.Max()
This should give you a starting point for your problem
You can try Regex like below :
string[] strArray1 = {"Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109"};
int[] num = strArray1.Where(v => Regex.IsMatch(v, #"^\d+$")).Select(int.Parse).ToArray();
int min = num.Min();
int max = num.Max();
As you don't want to use Regex, you can go with your solution, just do a small modification to get your desired result. Try this :
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
int[] num = Array.ConvertAll(strArray1, x =>
{
bool convertStrIntoInt = int.TryParse(x, out int result);
return result;
}).Where(x => x > 0).ToArray();
int max = num.OrderByDescending(c => c).ToArray()[0];
int min = num.OrderBy(c => c).ToArray()[0];
Here is another way to get int values from a string array into an int array.
Try it on dotnetfiddle.
public static class Extensions
{
public static int[] ToIntegerArray(this string[] sender)
{
var intArray = Array
.ConvertAll(sender,
(input) => new {
IsInteger = int.TryParse(input, out var integerValue),
Value = integerValue
})
.Where(result => result.IsInteger)
.Select(result => result.Value)
.ToArray();
return intArray;
}
}
Use
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
int[] intArray = strArray1.ToIntegerArray();
Array.Sort(intArray);
foreach (var value in intArray)
{
Console.WriteLine(value);
}
Console.WriteLine($"Min: {intArray.Min()}");
Console.WriteLine($"Max: {intArray.Max()}");
Targeting your intial question:
I don't [know] how to get the result outside of it to do a sort to find min and max values.
You simply can't get a complete solution for your Problem using ConvertAll() with a "normal" int.
So if we take a look at your result:
int[] num = Array.ConvertAll(strArray1, x =>
{
bool convertStrIntoInt = int.TryParse(x, out int result);
return result;
});
// num: int[8] { 0, 99, 0, 3, 0, 12, 0, 109 }
We can see each word will result in a 0, since 0 will be returned if the parsing failed - see: Int32.TryParse(...).
And therefore it is impossible to differentiate between an real 0 in your input or a word, which could not be parsed.
But we can tweek the convert a little bit by using Nullable<int>/int?
int?[] num = Array.ConvertAll(strArray1, x =>
{
return (int?)( int.TryParse(x, out int result) ? result : null);
});
// num: Nullable<int>[8] { null, 99, null, 3, null, 12, null, 109 }
So with this we are able to differ between a 0 and a word - represented by null.
Now you can perform other operations like num.Max() and num.Min().
If you need an int[] array, you have add some more function calls.
int[] num = Array.ConvertAll(strArray1, x =>
{
return (int?)( int.TryParse(x, out int result) ? result : null);
}).OfType<int>().ToArray();
//num: int[4] { 99, 3, 12, 109 }
So this is not quite optimal.
My solution for this would be a simple loop.
// Your intput
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
// Output Variables
List<int> result = new();
int min = int.MaxValue;
int max = int.MinValue;
// Loop
foreach( string item in strArray1)
{
if(int.TryParse(item, out int value))
{
result.Add(value);
min = min > value ? value : min;
max = max < value ? value : max;
}
}
// Output
// result: List<int>[4] { 99, 3, 12, 109 }
// min: 3
// max: 109
As already mentioned by Gian Paolo in the comments of this answer
working with a List<int> is much easier than working with an int[]
..., but if you really need an array, then you can just call ToArray().
int[] resultArray = result.ToArray();
Which results in int[4] { 99, 3, 12, 109 }.

How to convert the specific law of one-dimensional array into two-dimensional array?

Like this
string[] strarry = [12, 34, A1, FE, 12, 34, EA, 0, FE]
12 is the beginning ,
FE is the end,
Turn into
string strarry = [[12,34,A1,FE], [12,34,EA,0,FE]];
The distance from 12 to FE is not necessarily fixed (4)
How can I do it? Thank you
If I've understood you right (you want to obtain jagged array string[][] from ordinal one - string[]), you can try Linq in order to GroupBy items into subarrays:
using System.Linq;
...
string[] strarry = new string[]
{"12", "34", "A1", "FE", "12", "34", "EA", "0", "FE"};
// Here we exploit side effects, be careful with them
int groupIndex = 0;
string[][] result = strarry
.GroupBy(value => value == "FE" ? groupIndex++ : groupIndex)
.Select(group => group.ToArray())
.ToArray();
Let's have a look:
string report = string.Join(Environment.NewLine, result
.Select(line => "[" + string.Join(", ", line) + "]"));
Console.Write(report);
Outcome:
[12, 34, A1, FE]
[12, 34, EA, 0, FE]
I am not sure how applyable this code is for you, but maybe it gets you somewhere. Best of luck!
var strarry = "12, 34, A1, FE, 12, 34, EA, 0, FE";
var splittedArrays = strarry.Split(", FE", StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < splittedArrays.Length; i++)
{
if (splittedArrays[i][0].Equals(','))
{
splittedArrays[i] = splittedArrays[i].Substring(2);
}
splittedArrays[i] += ", FE";
Console.WriteLine(splittedArrays[i]);
}

Conversion of array string to array ulong in c#

I have a array of strings having values
string[] words = {"0B", "00", " 00", "00", "00", "07", "3F", "14", "1D"};
I need it to convert into array of ulong
ulong[] words1;
How should I do it in c#
I think I should add some background.
The data in the string is coming from textbox and I need to write the content of this textbox in the hexUpDown.Value parameter.
var ulongs = words.Select(x => ulong.Parse(x, NumberStyles.HexNumber)).ToArray();
If you need to combine the bytes into 64 bit values then try this (assumes correct endieness).
string[] words = { "0B", "00", " 00", "00", "00", "07", "3F", "14", "1D" };
var words64 = new List<string>();
int wc = 0;
var s = string.Empty;
var results = new List<ulong>();
// Concat string to make 64 bit words
foreach (var word in words)
{
// remove extra whitespace
s += word.Trim();
wc++;
// Added the word when it's 64 bits
if (wc % 4 == 0)
{
words64.Add(s);
wc = 0;
s = string.Empty;
}
}
// If there are any leftover bits, append those
if (!string.IsNullOrEmpty(s))
{
words64.Add(s);
}
// Now attempt to convert each string to a ulong
foreach (var word in words64)
{
ulong r;
if (ulong.TryParse(word,
System.Globalization.NumberStyles.AllowHexSpecifier,
System.Globalization.CultureInfo.InvariantCulture,
out r))
{
results.Add(r);
}
}
Results:
List<ulong>(3) { 184549376, 474900, 29 }

Group items of array by three using Linq

I have an Array of bytes, representing the RGB values of an image.
How could I group each offset of 3 values (RGB) of this array to apply my tweaks (like removing the repeated colors), maybe using Linq?
["120", "100", "10", "120", "100", "10", "10", "60", "110"]
to
["120", "100", "10", "10", "60", "110"]
You can use Select to add index to your enumeration and later group by index / 3. A bit of post-processing on each of the groups and you should be able to get what you want:
var grouped = source.Select((x,i) => new { x, i })
.GroupBy(x -> x.i / 3)
.Select(g => g.ToList())
.Select(g => new { R = g[0], G = g[1], B = g[2] })
.Distinct();
But that feels quite ugly. If I were you I'd probably write a simple custom LINQ method (an extension method on IEnumerable<int>) to do this more efficiently.
Shorter version that gets the distinct RGB values and their indexes:
string[] a = { "120", "100", "10", "120", "100", "10", "10", "60", "110" };
var l = Enumerable.Range(0, a.Length / 3)
.ToLookup(i => new { R = a[i * 3], G = a[i * 3 + 1], B = a[i * 3 + 2] });
If you don't mind using a loop instead of Linq:
class Program
{
static void Main(string[] args)
{
byte[] array = new byte[] { 120, 100, 10, 120, 100, 10, 10, 60, 110 };
List<byte[]> grouped = new List<byte[]>();
// This loop will populate the list grouped with arrays of 3 bytes each, each representing an value for RGB
for(int i = 0; i + 2 < array.Length; i += 3)
{
byte[] currentColor = new byte[]
{
array[i],
array[i + 1],
array[i + 2]
};
grouped.Add(currentColor);
}
// Here you will remove repeated elements for RGB
// Notice you will have to create the ByteArrayComparer class, you will find the code right under this one
var noRepeatedElements = grouped.Distinct<byte[]>(new ByteArrayComparer());
// Print the non repeated elements for testing purposes
foreach(var rgb in noRepeatedElements)
{
foreach(var value in rgb)
{
Console.Write($"\"{value}\"");
}
}
Console.ReadKey();
}
}
Where ByteArrayComparer is the following class
// This class will compare two distinct byte arrays and check if their elements are the same
public class ByteArrayComparer : IEqualityComparer<byte[]>
{
public bool Equals(byte[] x, byte[] y)
{
int smallerArrayLength = Math.Min(x.Length, y.Length);
bool elementsWithSameValue = true;
for(int i = 0; i < smallerArrayLength; i++)
{
// If there is a single element which is different, we know the arrays are different and can break the loop.
if(x[i] != y[i])
{
elementsWithSameValue = false;
break;
}
}
return elementsWithSameValue;
}
public int GetHashCode(byte[] obj)
{
int hash = 0;
for(int i = 0; i < obj.Length; i++)
{
hash += obj[i].GetHashCode();
}
return hash;
}
}
Note that grouped now is a List of arrays of bytes. Each element in grouped has three elements, representing a single RGB value.
Now you can work with the rgb values as you please.
Using Microsoft's Reactive Framework Team's Interactive Extensions (NuGet "Ix-Main") you can do this:
byte[] array = new byte[]
{
120, 100, 10, 120, 100, 10, 10, 60, 110
};
byte[] results =
array
.Buffer(3)
.Distinct(xs => String.Join(",", xs))
.SelectMany(x => x)
.ToArray();
That will give you { 120, 100, 10, 10, 60, 110 }.

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"))));

Categories

Resources