Related
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 }.
There is a string [] yield that can contain N count data. I have defined 15 count to be an example.
I want to divide these data into 6 groups.However, I cannot load the last remaining items into the array.
Where am I making a mistake?
string[] tags = {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"};
double tagLength = (int)Math.Floor(tags.Length / (double)6);
for (int i = 0; i <= tagLength-1; i++)
{
string[] groupArrays = new string[6];
Array.Copy(tags, i * 6, groupArrays, 0, 6);
}
The output i see
[0] = {1,2,3,4,5,6}
[1] = {7,8,9,10,11,12}
Should be output
[0] = {1,2,3,4,5,6}
[1] = {7,8,9,10,11,12}
[2] = {13,14,15}
I would suggest changing your code to calculate the number of groups you need to this:
int groups = (count / groupSize);
bool hasPartialGroup = count % groupSize != 0;
if (hasPartialGroup)
{
++groups;
}
The result of the first line will be integer division, so 15 / 6 will result in 2. We then see if there is a remainder using the remainder operator (%): count % groupSize. If its result isn't 0, then there is a remainder, and we have a partial group, so we have to account for that.
So for groups = 15 and groupSize = 6, we'll get count = 3. For groups = 12 and groupSize = 6, we'll get count = 2, etc.
Fixing your code to use this, it might look like:
string[] tags = {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"};
int count = tags.Length;
const int groupSize = 6;
int groups = (count / groupSize);
bool hasPartialGroup = count % groupSize != 0;
if (hasPartialGroup)
{
++groups;
}
for (int i = 0; i < groups; i++)
{
// you can't copy beyond the end of the array so we have to choose between the remaining ungrouped items and the group size
int currentGroupSize = Math.Min(tags.Length - i*groupSize, groupSize);
// I'm assuming for a partial group you only want this to be as big as the number of items.
// If you want it to always be 6 then change new string[currentGroupSize] to new string[groupSize] and you should be OK.
string[] groupArrays = new string[currentGroupSize];
Array.Copy(tags, i * groupSize, groupArrays, 0, currentGroupSize);
Console.WriteLine(string.Join(",", groupArrays));
}
Try it online // Example with fixed group size
Alternatively, you could create a batching helper method:
private static IEnumerable<T[]> BatchItems<T>(IEnumerable<T> source, int batchSize)
{
var collection = new List<T>(batchSize);
foreach (var item in source)
{
collection.Add(item);
if (collection.Count == batchSize)
{
yield return collection.ToArray();
collection.Clear();
}
}
if (collection.Count > 0)
{
yield return collection.ToArray();
}
}
This will collect batchSize number items together and then return one group at a time. You can read about how this works with yield return here.
Usage:
string[] tags = {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"};
List<string[]> batchedTags = BatchItems(tags, 6).ToList();
This will result in 3 string arrays, containing 1,2,3,4,5,6, 7,8,9,10,11,12, and 13,14,15.
You could also make this into an extension method.
Try it online
If you mean why you are not getting groups of 6, the reason for this is that you are flooring the length of tags / 6. So, if the last group has the length of less that 6, it won't get added. Add this to the end:
if (tags.Length%6!=0) { string[] groupArrays = tags[i..tags.Length] } // You can do this manually.
As said before, it's because you use Math.Floor(). Use either Math.Ceiling or remove the -1 from i<= taglength - 1.
Array.Copy will still produce errors when you're tags aren't an exact multiple of 6.
Below code should do the trick and won't produce an error
string[] tags = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" };
int baselength = 6;
double tagLength = (int)Math.Floor(tags.Length / (double)6);
int length = baselength;
for (int i = 0; i <= tagLength; i++)
{
string[] groupArrays = new string[baselength];
if (i == tagLength)
length = ((i + 1) * length) - tags.Length;
if(length > 0 && length < baselength)
Array.Copy(tags, i * 6, groupArrays, 0, length);
}
Because you use Math.Floor(...). You should use Math.Ceiling(...) instead.
(int)Math.Floor(15d / 6d) // returns 2 >> 2 groups.
(int)Math.Ceiling(15d / 6d) // returns 3 >> 3 groups.
Beware though, you will get an ArgumentOutOfRangeException in Array.Copy, since index 3 * 6 does not exist. You will have to find a way around that.
One possible solution:
string[] tags = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" };
double tagLength = (int)Math.Ceiling(tags.Length / (double)6);
for (int i = 0; i <= tagLength - 1; i++)
{
int arrLength = (i + 1) * 6 <= tags.Length ? 6 : tags.Length % 6;
string[] groupArrays = new string[arrLength]; // or six if you always want a length of 6
Array.Copy(tags, i * 6, groupArrays, 0, arrLength);
}
Or using Linq:
for (int i = 0; i < (int)Math.Ceiling(tags.Length / 6d); i++)
{
string[] groupArrays = tags.Skip(i * 6).Take(6).ToArray();
}
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
What to use in order to get the number of elements in each line. The example of the text file is given below. All I want to do is to get the number of elements in each line. Like the first line would have 4 elements, the second one 3 and so on.
1 5 4 6
2 4 6
1 9 8 7 5 3
3 2 1 1
private static void Skaitymaz(Trikampis[] trikampiai)
{
string line = null;
using (StreamReader reader = new StreamReader(#"U2.txt"))
{
string eilute = null;
while (null != (eilute = reader.ReadLine()))
{
int[] values = eilute.Split(' ');
}
}
}
Try,
string line = null;
using (StreamReader reader = new StreamReader(#"U2.txt"))
{
string eilute = null;
while (null != (eilute = reader.ReadLine()))
{
string[] values = eilute.Split(' ');
int noOfElement = values.Length;
}
}
You need to get length of the array after split,
values.Length
Something like that (Linq): read each line, split it by space or, probably, tabulation and count the items:
var numbers = File
.ReadLines(#"C:\MyText.txt")
.Select(line => line.Split(new Char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries).Length);
// Test: 4, 3, 6, 4
Console.Write(String.Join(", ", numbers));
I am making a quiz and have pulled a series of strings from a text file and added them a list, further separating the file info into individual strings. My question is, how would I make the individual strings correspond to a numerical value? For example A = 1, B = 2, so on and so forth.
The following code depicts the creation of the list and the adding of elements:
List<string> keyPool = new List<string>();
OpenFileDialog keyLoad = new OpenFileDialog();
keyLoad.Multiselect = false;
if (keyLoad.ShowDialog() == DialogResult.OK)
{
foreach (String fileName in keyLoad.FileNames)
{
key = File.ReadAllText(fileName);
kLabel.Text = ("Key:" + System.Environment.NewLine);
k1 = key.Split(new string[] { System.Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries)[0];
keyPool.Add(k1);
k2 = key.Split(new string[] { System.Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries)[1];
keyPool.Add(k2);
k3 = key.Split(new string[] { System.Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries)[2];
keyPool.Add(k3);
k4 = key.Split(new string[] { System.Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries)[3];
keyPool.Add(k4);
k5 = key.Split(new string[] { System.Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries)[4];
keyPool.Add(k5);
k6 = key.Split(new string[] { System.Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries)[5];
keyPool.Add(k6);
k7 = key.Split(new string[] { System.Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries)[6];
keyPool.Add(k7);
k8 = key.Split(new string[] { System.Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries)[7];
keyPool.Add(k8);
k9 = key.Split(new string[] { System.Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries)[8];
keyPool.Add(k9);
k10 = key.Split(new string[] { System.Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries)[9];
keyPool.Add(k10);
}
}
How would this be done?
In general terms, you are looking for a dictionary. In this case, we are using it to define the mapping between strings and numbers:
Dictionary<string, int> mapping = new Dictionary<string, int>();
mapping.Add("A", 1);
...
int value = mapping["A"];
You could take advantage of the ASCII table if you just want to convert the first few capital letters to numbers:
int value = (int)stringValue[0] - (int)'A' + 1;
Assuming each "string" is a single letter, such as A, B, and so on, you can set up an enum and parse each letter into it's appropriate enum value:
public enum Letter
{
A = 1,
B = 2,
C = 3,
D = 4,
E = 5,
F = 6,
G = 7,
H = 8,
I = 9,
J = 10
}
You only have to split the string once, it puts all values into an array, and you can foreach through that and build up your list:
List<Letter> keyPool = new List<Letter>();
var letters = key.Split(new string[] { System.Environment.NewLine },
System.StringSplitOptions.RemoveEmptyEntries);
foreach(var letter in letters)
{
keyPool.Add((Letter)Enum.Parse(typeof(Letter), letter);
}
To convert and use it as an int, you can just cast it:
Letter letter = Letter.A;
int a = (int)letter;
use an enum
enum Keys
{
A=1,
B,
C,
//continue onward
}
To convert to/from string:
string s = Keys.B.ToString();
Keys key = (Keys)Enum.Parse(typeof(Keys), s);
To convert to/from int:
int i = (int)Keys.B;
Keys keyFromI = (Keys)i;
You don't need to add enum or dictionary for the alphabet !
static void Main(string[] args)
{
string intialString = "abc".ToUpper();
string numberString = "";
foreach (char c in intialString)
{
numberString += (int)c - 64;
}
Console.WriteLine(numberString);
}
Here is clear example. If you want use it !