C# LINQ: How is string("[1, 2, 3]") parsed as an array? - c#

I am trying to parse a string into array and find a very concise approach.
string line = "[1, 2, 3]";
string[] input = line.Substring(1, line.Length - 2).Split();
int[] num = input.Skip(2)
.Select(y => int.Parse(y))
.ToArray();
I tried remove Skip(2) and I cannot get the array because of non-int string. My question is that what is the execution order of those LINQ function. How many times is Skip called here?
Thanks in advance.

The order is the order that you specify. So input.Skip(2) skips the first two strings in the array, so only the last remains which is 3. That can be parsed to an int. If you remove the Skip(2) you are trying to parse all of them. That doesn't work because the commas are still there. You have splitted by white-spaces but not removed the commas.
You could use line.Trim('[', ']').Split(','); and int.TryParse:
string line = "[1, 2, 3]";
string[] input = line.Trim('[', ']').Split(',');
int i = 0;
int[] num = input.Where(s => int.TryParse(s, out i)) // you could use s.Trim but the spaces don't hurt
.Select(s => i)
.ToArray();
Just to clarify, i have used int.TryParse only to make sure that you don't get an exception if the input contains invalid data. It doesn't fix anything. It would also work with int.Parse.
Update: as has been proved by Eric Lippert in the comment section using int.TryParse in a LINQ query can be harmful. So it's better to use a helper method that encapsulates int.TryParse and returns a Nullable<int>. So an extension like this:
public static int? TryGetInt32(this string item)
{
int i;
bool success = int.TryParse(item, out i);
return success ? (int?)i : (int?)null;
}
Now you can use it in a LINQ query in this way:
string line = "[1, 2, 3]";
string[] input = line.Trim('[', ']').Split(',');
int[] num = input.Select(s => s.TryGetInt32())
.Where(n => n.HasValue)
.Select(n=> n.Value)
.ToArray();

The reason it does not work unless you skip the first two lines is that these lines have commas after ints. Your input looks like this:
"1," "2," "3"
Only the last entry can be parsed as an int; the initial two will produce an exception.
Passing comma and space as separators to Split will fix the problem:
string[] input = line
.Substring(1, line.Length - 2)
.Split(new[] {',', ' '}, StringSplitOptions.RemoveEmptyEntries);
Note the use of StringSplitOptions.RemoveEmptyEntries to remove empty strings caused by both comma and space being used between entries.

I think it would be better you do it this way:
JsonConvert.DeserializeObject(line, typeof(List<int>));

you might try
string line = "[1,2,3]";
IEnumerable<int> intValues = from i in line.Split(',')
select Convert.ToInt32(i.Trim('[', ' ', ']'));

Related

Trouble Converting string [] to int []

using System;
using System.IO;
namespace Test_Arrays_and_Files
{
class Program
{
static void Main(string[] args)
{
string tFile = #"C:\Programming\GLO\DC\dcw.txt";
string read = File.ReadAllText(tFile);
string[] test = read.Split(',');
int[] ints = Array.ConvertAll(test, int.Parse);
Console.WriteLine(ints[0]);
}
}
}
Input Data:
Text File Contents:(1 value per line,)
35,
35,
40,
40,
40,
getting System.FormatException: Input string was not in correct format
please help and sorry for bad post I'm new here
There are two issues in your code,
Your string is ending with , which is creating empty record after the split. This is the reason you are getting the error.
Your delimiter could be $",{Environment.NewLine}" not only ','.
So to convert given string to int array, first Trim() the input string by , and then split by $",{Environment.NewLine}".
Like,
using System.Linq;
...
var result = str.Trim(',') //Remove leading and trailing comma(s), You can use `TrimEnd()` as well
.Split($",{Environment.NewLine}", StringSplitOptions.RemoveEmptyEntries) //Split by given delimiter.
.Select(int.Parse)
.ToArray(); //Convert string[] to int[]
Try online
You're only getting it because the file has a comma at the end, which means Split ends up churning out an empty string in the very last position. int.Parse will choke on the empty string
Plenty of ways you could solve it, one is to tell Split not to return you empties, by changing the split line of your code to:
string[] test = read.Split(new[]{','}, StringSplitOptions.RemoveEmptyEntries);
You could instead trim the comma off the end, but using the above approach would mean your parsing would survive a blank line in the middle of the file too so overall it's more robust
Generally when parsing strings it's more robust to use TryParse than Parse. TryParse takes in the number variable to set the result to and returns you a Boolean telling if the parsing succeeded
int[] ints = Array.ConvertAll(test, GetIntOrMinusOne);
//put a method helper
private int GetIntOrMinusOne(string s){
if(int.TryParse(s, out var t)
return t;
return -1;
}
For this we need to get a bit more involved with the ConvertAll call. Instead of telling ConvertAll to call a "method that converts a string to an int" like int.Parse, we need to write our own mini method that tries to parse and if it fails return something like -1, then nominate that as the method to call to do the conversion, not int.Parse
It's important to note that this would introduce -1 into the resulting int[] array wherever there was bad data in the string array.. In your later processing you would then do some check to avoid them (such as skipping them)
You can shorten that code above by turning the method into a lambda:
int[] ints = Array.ConvertAll(test, s => int.TryParse(s, out var t) ? t : -1);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
a lambda; "just the important parts of a method"
But I'm not sure that you'll have come across lambdas yet, judging by the style of the rest of the code

FormatException on String to Int.ToList Conversion

string aresultlist = File.ReadAllLines(data).ToString();
var bresultlist = aresultlist.Split().Select(s => Convert.ToInt32(s));
List<int> resultlist = bresultlist.ToList();
Can anyone help with the FormatException I keep getting on this block, "It's the datetime Format, take date first exception". It's a string read from a space delimited text file.
Try this:
List<int> resultList = File
.ReadLines(data) // you've got IEnumerable<string>
.Select(line => line.Split()) // -/- IEnumerable<string[]>
.Select(ietms => int.Parse(items[0])) // -/- IEnumerable<int>
.ToList(); // finally, it's List<int>
I've assumed that it's the 1st item of the line which should be converted into int: int.Parse(items[0]), change 0 into the right index if required.
Try avoiding ReadAllLines in favor to ReadLines: you don't what all the file (which can be long) to be read into an array in one go
the problem is that ReadAllLines returns a string[]. If you call ToString on such an object you get the namespace.classname as a string. So in your case:
System.String[]
splitting this string results definetely not a number. But in a string[] with on entry, namely:
System.String[]
If your file has only one line with the space delimited numbers, I would suggest to use File.ReadAllText. It will read the entire content of the file and return it as 1 string. This way you can use your code almost as it is.
string aresultlist = File.ReadAllText(data);
var bresultlist = aresultlist.Split().Select(s => Convert.ToInt32(s));
List<int> resultlist = bresultlist.ToList();
EDIT:
As suggested by Gilad Green you might have content in the file that cannot be parsed to a number and will throw an exception. To avoid this you can follow this example

How to convert String to int [] array in c#?

Am looking for the code which need to convert string to int array so far what i done is :
string text = "[1,2]";
int[] ia = text.Split(';').Select(n => Convert.ToInt32(n)).ToArray();
But am getting number format exception how to get rid of this here is the string "[1,2]" need to convert into [1,2] how can i achieve this it may be dumb question but need to solve this.
Just a piece of cake using JsonConvert,
int[] arr = JsonConvert.DeserializeObject<int[]>(text);
Just Trim the string's '[' and ']' and split by ',' to get it as array.
Then convert it to int array using 'Array.ConvertAll' method.
string s = "[1,2]";
string[] s1 = s.Trim('[', ']').Split(',');
int[] myArr = Array.ConvertAll(s1, n => int.Parse(n));
Replace the braces [] with empty string and then apply Split function.
objModellead.ServiceCatalogID
.Replace("[","")
.Replace("]","")
.Split(';')
.Select(int.Parse)
.ToArray()

What is the best way to create a Comma separated String from numbers in a short[] Array in C#?

I have a short[] Numbers;
Now I want to convert the numbers in the array into a string with each array value separated by a comma. How do I do this in C#?
short[] Numbers = {1, 2, 3, 4};
I want this as a string "1,2,3,4" to store in the database.
PS: I checked many questions in SO for the same topic but did not get exact match. Hence I am asking this one
Try the following
string result = String.Join(",", Numbers);
Note: this won't work in 3.5 or earlier because String.Join lacks the necessary overloads. To use this API the code would need to change to
string result = String.Join(",", Numbers.Select(x => x.ToString()).ToArray());
String result = string.Join(",", Numbers);
It can be done using LINQ -
string result = String.Join(",", Numbers.Select(p=>p.ToString()).ToArray());
EDIT -
string result = String.Join(",", Numbers);
As pointed out by Jean Hominal below, the Select and the ToArray can be removed due to the String.Join<T>(String, IEnumerable<T>) overload.

Failed to use SUBSTRING in TryParse

I found an error in my code, where the subtring is not work, it says "startIndex cannot be larger than the length of string"
static int MyIntegerParse(string possibleInt)
{
int i;
return int.TryParse(possibleInt.Substring(2), out i) ? i : 0;
}
I used the procedure here:
var parsed = File.ReadLines(filename)
.Select(line => line.Split(' ')
.Select(MyIntegerParse)
.ToArray())
.ToArray();
But I don't understand why it's error because I already used the substring before and it's work, can I ask for a help here? thnaks.
sample string:
10192 20351 30473 40499 50449 60234
10192 20207 30206 40203 50205 60226
10192 20252 30312 40376 50334 60252
Substring will fail when possibleInt contains fewer than two characters, so you should add that test to your code as well. I suspect that you Split call produces an empty string during some circumstances. This empty string is passed into your int-parser which then fails on the Substring call. So, you should probably do two things:
Get rid of empty strings in the splitting
Handle short or empty strings deliberately in your parsing code
Getting rid of empty strings is quite easy:
var parsed = File.ReadLines(filename)
.Select(line => line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
.Select(MyIntegerParse)
.ToArray())
.ToArray();
Adding deliberate handling of empty strings can be done like so:
static int MyIntegerParse(string possibleInt)
{
if (string.IsNullOrEmpty(possibleInt) || possibleInt.Length < 2)
{
return 0;
}
int i;
return int.TryParse(possibleInt.Substring(2), out i) ? i : 0;
}
...or if you are a fan of compact and hard-to-read constructs:
static int MyIntegerParse(string possibleInt)
{
int i;
return (!string.IsNullOrEmpty(possibleInt)
&& possibleInt.Length >= 2
&& int.TryParse(possibleInt.Substring(2), out i)) ? i : 0;
}
No, I have chosen to return 0 when I get strings that are too short. In your case it might make more sense to return some other value, throw an exception or use a Debug.Assert statement.
The possibleInt string needs to be at least two characters long. When it isn't then you'll see the error that you've described.
Add this before your return statement and see if that helps you figure out what's going on:
Debug.Assert(!string.IsNullOrEmpty(possibleInt) && possibleInt.Length > 2);
When running in Debug mode this will throw an exception if the two cases above are not met.
You could also use a Code Contract like this:
Contract.Assert(!string.IsNullOrEmpty(possibleInt) && possibleInt.Length > 2);
You are getting this exception because you are trying to get the substring of a string starting at an index that is greater than the length of the string.
someString.Substring(x) will give you the substring of someString starting at position x in the string, and it is zero based. You are getting this exception because in this case 2 is outside the range of the particular strings length.
Stick a try catch around it, or a breakpoint and you will see the string that is causing this exception has a length less than 3.
The line you are attempting to parse is not that long. From the C# Specification on Substring:
The zero-based starting character position of a substring in this instance.
The string you are passing in either has 0 or 1 characters in it. You need to modify your code to handle such a situation.
EDIT: Additionally, you should be removing empty elements from your file using an overload of split:
.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntires)

Categories