convert string[] to int?[] - c#

how to convert a string array to nullable integer array.

Well, the two aspects are:
How do you convert an array from one type to another?
How do you convert a string to a nullable int?
The first is simple - you can use Array.ConvertAll, passing in an Converter delegate. There's the LINQ way as well (x.Select(...).ToArray()), but that's slightly less efficient if you know you've got an array to start with and you want an array out of the other end 1.
The string to int? is probably best done in a method. You can do it in an anonymous function, but in this particular case I'd use a separate method. I rarely like to have to declare variables in an anonymous function.
public static int? TryParseInt32(string text)
{
int value;
return int.TryParse(text, out value) ? value : (int?) null;
}
To answer the comment, yes you need the cast 2.
or without the conditional:
public static int? TryParseInt32(string text)
{
int value;
if (int.TryParse(text, out value))
{
return value;
}
else
{
return null;
}
}
Put them together like this:
string[] x = {"15", "10", "hello", "5" };
int?[] y = Array.ConvertAll(x, TryParseInt32);
1 Array.ConvertAll is more efficient than x.Select().ToArray() because it has more information. It can create the final array immediately - no resizing is ever required. Calling Enumerable.ToArray() (with the result of Select()) doesn't have the same information, so it effectively has to add the results to a List<T> (potentially resizing several times along the way) and then usually resize at the end as well. (It doesn't actually use List<T> but the concepts are the same.) It's definitely worth knowing about the Select/ToArray solution, but I don't think it's actually any more readable than ConvertAll in this case, so you might as well use the more efficient form.
2 The reason you need the cast in the conditional is because the compiler doesn't know what type of "null" you really mean - but it knows it can't convert from null to an int. The type of the conditional expression has to be either the type of the second operand or the type of the third operand, and the other one has to be implicitly convertibly. By forcing the third operand to be of type int? here everything is fine - because you can implicitly convert from int to int?. Note that the compiler doesn't take the way you're using the expression to try to work out the type. Another alternative is to use new int?() instead of null.

By parsing and using Linq:
string[] input = { "1", "3", "x" }
var result = input.Select(
s => { int i; return (int.TryParse(s, out i)) ? i : (int?) null; }).ToArray();
… but I grant that this is a bit cryptic. I wouldn’t use a lambda expression here. For clarity, this should belong to a proper function ParseNullableInt. Then you can call it like this:
var result = input.Select(ParseNullableInt).ToArray();

Edit: I removed the null/empty check because TryParse properly handles those cases by returning false.
string[] stringArray = ...;
int?[] nullableIntArray = Array.ConvertAll(stringArray,
s =>
{
int value;
if (!int.TryParse(s, out value))
return default(int?);
return (int?)value;
});

One option would be this (I'm presuming that you want nulls for the values that were not integer values):
public static class StringArrayExtension
{
public static int?[] ToNullableIntArray(this string[] array)
{
int?[] result = new int?[array.Length];
for (int index = 0; index < array.Length; index++)
{
string sourceValue = array[index];
int destinationValue;
if (int.TryParse(sourceValue, out destinationValue))
{
result[index] = destinationValue;
}
else
{
result[index] = null;
}
}
return result;
}
}
usage:
string[] source = { "hello", "1", "3.1415", "20", "foo" };
int?[] dest = source.ToNullableIntArray();

You need to use int.TryParse:
string[] s = { "123", "a", "45" };
int?[] result = new int?[s.Length];
for (int i = 0; i < s.Length; ++i)
{
int a;
if (int.TryParse(s[i], out a))
result[i] = a;
}

List<int?> ints = new List<int?>();
foreach (string str in strs)
{
int val;
if (int.TryParse(str, out val))
{
ints.Add(val);
}
else { ints.Add(null); }
}
return ints.ToArray();

An integer array can not be null. In fact every element in Integer Array will have "0" by default.
Regarding Conversion
Create an Integer array of the same length or an arraylist
int [] _arr=new int[strArray.length];
for(int i=0;i<strArray.length;i++]
{
if(String.IsNullOrEmpty(strArray[i]))
{
_arr[i]=0;
}
else
{
_arr[i]=int.Parse(strArray[i]);
}
}

Related

C# string[] arrayA return null value in arrayA[3]

I have many array in my code, example;
string[] arrayA = new string[31];
and i need to put the value from the arrays into SQL Database
SqlCommand commA = new SqlCommand("INSERT INTO dbo.DatabaseA" +
" (ColumnA) VALUES" +
" (#ColumnA)", connA);
commA.Parameters.Add("#ColumnA", SqlDbType.NVarChar).Value = arrayA[3];
Why does the #ColumnA return error 'the value is not supplied' or to be precise arrayA[3] = null? I always thought unassigned string[] have "" as initial value.
If initially i assigned arrayA[3] = "" before the SQLCommand the code work just fine.
Is there a way to populate the all string[] arrayAwith "" without using for loop?
From the code supplied there is no value assigned to arrayA[3] the array is simply a container for values and sets each value to the default value for the type similar to going default(string).
Now as string is a reference type the default value for the string is null however a value type int for example will have a default value of 0.
We can easily test this such as.
string[] arrayA = new string[31];
var s = arrayA[3]; //is null as string is a reference type
int[] arrayB = new int[31];
var i = arrayB[3]; //equals 0 as default(int) = 0
Now as pointed in comments there are easy ways to populate an array and the referenced comment points to How to populate/instantiate a C# array with a single value?
The snippet below is from the answer above
public static void Populate<T>(this T[] arr, T value ) {
for ( int i = 0; i < arr.Length;i++ ) {
arr[i] = value;
}
}
This can be called by:
arrayA.Populate("");
So in the call:
commA.Parameters.Add("#ColumnA", SqlDbType.NVarChar).Value = arrayA[3];
In fact arrayA[3] = null
EDIT
The snippet above is an extension method (as seen by the this keyword on the first parameter in the method signature). This must be in a static class similar to below.
public static class ArrayExtensions
{
public static void Populate<T>(this T[] arr, T value)
{
for (int i = 0; i < arr.Length; i++)
{
arr[i] = value;
}
}
}
As for the question
Is there a way to populate the all string[] arrayAwith "" without
using for loop?
All the methods to set the default value of all items in an array will require a loop of some sort and the loop may be a foreach or for under the hood somewhere.
You could also create a method that would create an array for you of a specified size with a default value.
public static T[] CreateArray<T>(int capacity, T defaultValue)
{
var array = new T[capacity];
array.Populate(defaultValue);
return array;
}
Which could then be called as:
var arrayC = ArrayExtensions.CreateArray<string>(31, "");
s = arrayC[3]; //equals ""
However that starts to look too lazy to me.
You are not assigned any values to the array . If you need " " ,if there is no value use conditional operators .
arrayA[3]==null?"":arrayA[3];
conditional operators

Simple Way to Read Integers from a File

I am trying to read in a file which is essentially a list of integers, seperated by a line. Obviously, file input can never be trusted so I need to filter out non-integers.
1
2
3
4
I know the as operator usually converts if it can and then assigns a null, however because int isn't nullable this isn't the case. I thought that perhaps I could cast to Nullable<int>. I have never really delved into this, I thought perhaps I could do:
var lines = File.ReadAllLines("");
var numbers = lines.Select(line => line as int?).Where(i => i != null);
I know that I could get potentially get around this by doing:
var numbers = lines.Select(line =>
{
int iReturn = 0;
if (int.TryParse(line, out iReturn ))
return iReturn;
else
return null;
}).Where(i => i != null);
I also could potentially do it as an extension method.
I was just looking for a neat, concise way of doing the cast in a statement and also understanding why my code is invalid.
I'm always using this simple extension method:
public static int? TryGetInt(this string item)
{
int i;
bool success = int.TryParse(item, out i);
return success ? (int?)i : (int?)null;
}
Then it's easy:
var numbers = lines.Select(line => line.TryGetInt())
.Where(i => i.HasValue)
.Select(i => i.Value);
You can also use int.TryParse without the extension, but that is undocumented hence might stop working in future:
int i = 0;
var numbers = lines.Where(line => int.TryParse(line, out i))
.Select(line => i);
Edit
"also understanding why my code is invalid"
relevant code:
if (int.TryParse(line, out iReturn ))
return iReturn;
else
return null;
It would work if you'd replace
else
return null;
with
else
return (int?)null;
because you are returning an int, but null is not convertible implicitly to an int.
There isn't a concise way to do this because here you don't need to cast (you cannot cast) -- you need to convert from one type to another. The types of course are int and string (so not exactly "any" types), but as in the general case any conversion between unrelated types cannot be done "just like that".
Nope. C# is deliberately cautious about changing strings to numbers.
You can make your code shorter (no more nulls) using a foreach loop
var numbers = new List<int>();
foreach(string line in lines)
{
int n;
if (int.TryParse(line, out n))
numbers.Add(n);
}
If I understand you correctly and you want just filter the non integer lines, maybe regex is an option?
var lines = File.ReadAllLines("");
var numbers = lines.Where(i => Regex.IsMatch(i, "[0-9]+"));
Here's the best I came up with:
Use this extension method:
public static class Int32Extensions
{
public static int? ParseOrDefault(this string text)
{
int iReturn = 0;
if (int.TryParse(text, out iReturn))
{
return iReturn;
}
return null;
}
}
Like this:
var query = lines.Select(x => x.ParseOrDefault()).Where(x => x.HasValue);
You can create and extension method
public static int? ToInt(this string s, int default){ ... }
and use it in LINQ:
var lines = File.ReadAllLines(path);
var numbers = lines.Select(line => line.ToInt())
.Where(i => i != null);

How to handle Index out of range in a better way

My code was giving me Index out of Range exception for a certain input. Below is the problematic code:
string[] snippetElements = magic_string.Split('^');
string a = snippetElements[10] == null ? "" : "hello";
string b = snippetElements[11] == null ? "" : "world";
For that particular input, array snippetElements had only one element in it, hence while trying to index 10th and 11th element, I got the exception.
For now, I have introduced the following check:
if (snippetElements.Length >= 11)
{
string a = snippetElements[10] == null ? "" : "hello";
string b = snippetElements[11] == null ? "" : "world";
}
Can someone suggest a better way to write this check. Somehow the number 11 is not looking good in the code.
Yes this is an old post, but still helpful. You could use this which I think is cleaner:
string a = snippetElements.ElementAtOrDefault(10) ?? "hello";
string b = snippetElements.ElementAtOrDefault(11) ?? "world";
Can someone suggest a better way to write this check. Somehow the
number 11 is not looking good in the code.
Well you are accessing the element with 11 index, if you have that index in your variable then you can use that in your check, otherwise 11 is fine in your check. Your check should be if(index < snippetElements.Length)
Something like:
int index = 11;
if(index < snippetElements.Length)
{
string b = snippetElements[index] == null ? "" : "world";
}
snippetElements[11] is the 12th element.
if (snippetElements.Length >= 12)
As long your are actually using the [10] and [11] indexes it doesn't look wrong to use the 12 in the if statement.
You can generalize the problem to an extension method like this:
public static class ArrayExtensions
{
public static bool TryIndex<T>(this T[] array, int index, out T result)
{
index = Math.Abs(index);
result = default(T);
bool success = false;
if (array != null && index < array.Length)
{
result = (T)array.GetValue(index);
success = true;
}
return success;
}
}
And convert your code to:
string[] snippetElements = magic_string.Split('^');
string a = null;
string b = null;
if (snippetElements.TryIndex(10, out a) && snippetElements.TryIndex(11, out b))
{
}
Or, more like your source code and using the TryIndex(...) extension method:
string[] snippetElements = magic_string.Split('^');
string a = null;
string b = null;
snippetElements.TryIndex(10, out a);
snippetElements.TryIndex(11, out b);
a = a ?? "hello"; // Null coalesence ?? operator is great!
b = b ?? "world";
It makes the array indexed access safer since your code won't never throw ArgumentOutOfRangeException.
Note that this extension method will work for any kind of array, regardless of its type! Either if its a value type (int, byte...) or a reference type (string, your own classes...).
The logic here is wrong.
If your Split method produces less than 12 elements your indexing on the array snippetElements could go only from zero to (Length - 1) of the array.
In that case there aren't elements at index 10 or 11. And, in any case, if the snippetElement.Lenght is equal or greater than 12, then the elements in the array can't be null. Or they contain a string or they will be empty strings.
You could just write
string a = snippetElements.Length >= 12 ? "hello" : string.Empty;
string b = snippetElements.Length >= 12 ? "world" : string.Empty;
It might be late now, but for any one else who's having the same problem, that's how I solved it. I usually use this logic inside a for loop.
int index = 10;
string a = (index < snippetElements?.Length) ? snippetElements[index] : string.Empty;
snippetElements?.Length checks if snippetElements is not empty then it calls its Length property. Accessing Length property of an empty array results in an exception.
snippetElements[index] (you could replace this with "hello" as in your example) is accessed only if the index is in the bound of an array. Otherwise, it assigns String.Empty to a.

how to handle double.NaN for Generic method accepting IComparable in C#

I have a generic GetMinimum method. It accepts array of IComparable type (so it may be string[] or double[]). in the case of double[] how can I implement this method to ignore the double.NaN values? (I'm looking for good practices)
when I pass this array
double[] inputArray = { double.NaN, double.NegativeInfinity, -2.3, 3 };
it returns the double.NaN!
public T GetMinimum<T>(T[] array) where T : IComparable<T>
{
T result = array[0];
foreach (T item in array)
{
if (result.CompareTo(item) > 0)
{
result = item;
}
}
return result;
}
Since both NaN < x and NaN > x will always be false, asking for the minimum of a collection that can contain NaN is simply not defined. It is like dividing by zero: there is no valid answer.
So the logical approach would be to pre-filter the values. That will not be generic but that should be OK.
var results = inputArray.EliminateNaN().GetMinimum();
Separation of concerns: the filtering should not be the responsibility (and burden) of GetMinimum().
You can't from inside the method. The reason is you have no idea what T can be from inside the method. May be you can by some little casting, but ideally this should be your approach:
public T GetMinimum<T>(T[] array, params T[] ignorables) where T : IComparable<T>
{
T result = array[0]; //some issue with the logic here.. what if array is empty
foreach (T item in array)
{
if (ignorables.Contains(item)
continue;
if (result.CompareTo(item) > 0)
{
result = item;
}
}
return result;
}
Now call this:
double[] inputArray = { double.NaN, double.NegativeInfinity, -2.3, 3 };
GetMinimum(inputArray, double.NaN);
If you're sure there is only item to be ignored, then you can take just T as the second parameter (perhaps as an optional parameter).
Or otherwise in a shorter approach, just:
inputArray.Where(x => !x.Equals(double.NaN)).Min();
According to this Q&A, it's complicated: Sorting an array of Doubles with NaN in it
Fortunately, you can hack around it:
if( item is Single || item is Double ) {
Double fitem = (Double)item;
if( fitem == Double.NaN ) continue;
}

C# Split a string of integers into an IEnumerable<int>

I need to convert a string of comma separated integers into a list of integers.
What is the best way to do this?
I can do it below but am worried about the performance - Is there a better more efficient way to do this?
public IEnumerable<int> GetListOfIds()
{
string Ids = "1,4,5,7,12"; // would be passed into method
List<int> _result = Ids.Split(',')
.ToList()
.Select(item => int.Parse(item))
.ToList();
return _result;
}
There's no need to call ToList, but otherwise your code looks fine:
public IEnumerable<int> GetListOfIds(string ids)
{
return ids.Split(',').Select(item => int.Parse(item));
}
You may also want to consider adding error handling in case the input string is invalid:
public IEnumerable<int> GetListOfIds(string ids)
{
foreach (string part in ids.Split(','))
{
int x;
if (!int.TryParse(part, out x))
{
throw new ArgumentException(
string.Format("The value {0} cannot be parsed as an integer.", part),
"ids");
}
else
{
yield return x;
}
}
}
You may at least omit first ToList() statement - so it will be
List<int> _result = Ids.Split(',').Select(item => int.Parse(item)).ToList();
You can probably loop on the split result and do a yield return int.Parse... but I would not expect big differences unless you have really many items in the original string.
Use the Stringify.Library nuget package
Example 1 (Default delimiter is implicitly taken as comma)
var ids = "1, 4, 5, 7, 12";
var splitComma = new StringConverter().ConvertTo<List<int>>(ids);
Example 2 (Specifying the delimiter explicitly)
var ids = "1; 4; 5; 7; 12";
var splitColon = new StringConverter().ConvertTo<List<int>>(ids, new ConverterOptions { Delimiter = ';' });

Categories

Resources