2

I have a string that I take from a property of an object. I split IT into a list of strings that I then want to cast into a list of ints.

This is what the code looks like:

TheListOfInts = s.TheListOfStrings
  .Split(',')
  .ToList()
  .Select(g => Convert.ToInt32(g))
  .ToList();

I'm getting an error

Input string was not in a correct format.

The problem is that sometimes TheListOfStrings is ;null; and I think that's what triggers the error. What can I add in the lambda to take into account the possibility of a null string?

halfer
  • 19,824
  • 17
  • 99
  • 186
frenchie
  • 51,731
  • 109
  • 304
  • 510
  • 1
    Read the error message. That has nothing to do with `null`. Look at what your string actually contains. – SLaks Dec 21 '17 at 15:36
  • 4
    Use `StringSplitOptions.RemoveEmptyEntries` – JohnyL Dec 21 '17 at 15:38
  • Please post a [mcve]. We can only guess what the strings look like and thus what the actual problem is. My guesses would be that you either have empty strings in there, or spaces before/after the numbers. – Lasse V. Karlsen Dec 21 '17 at 15:47
  • https://stackoverflow.com/questions/1297231/convert-string-to-int-in-one-line-of-code-using-linq/37033140#37033140 – Slai Dec 21 '17 at 16:09

2 Answers2

2

When parsing a string to an int you want to use int.TryParse to make sure it won't throw an exception. In linq you can do it this way:

var result = s.TheListOfStrings.Split(',')
              .Select(i => (int.TryParse(i, out var value), value))
              .Where(pair => pair.Item1) // remove items that failed to be parsed
              .Select(pair => pair.value) // take the parsed value
              .ToList();

This fixes the cases of the empty items from the split (you can still add the RemoveEmptyEntries flag) and also, in case an item is not a valid integer it won't parse it.

Notice that the first ToList() that you added is not needed.


As you are using a pre C# 7.0 version then you should:

int value;
var result = s.TheListOfStrings.Split(',')
              .Select(i => new { Succeeded = int.TryParse(i, out value), Value = value })
              .Where(pair => pair.Succeeded) // remove items that failed to be parsed
              .Select(pair => pair.Value) // take the parsed value
              .ToList();

Difference:


In your question you stated: The problem is that sometimes TheListOfStrings is null and I think that's what triggers the error.

This will not be the cause for the error as if it was you would have received a NullReferenceException.

To cope with that you can:

  1. Use the ?. operator (and then the result might be null instead of an empty collection.
  2. Check if it is null:

    var result = s.TheListOfStrings == null ? 
                     Enumerable.Empty<int> () : 
                     /*The linq query above*/;
    
Gilad Green
  • 36,708
  • 7
  • 61
  • 95
  • Looks like value it doesn't like the first .Select statement; var value – frenchie Dec 21 '17 at 16:01
  • @frenchie What C# version are you using? – Gilad Green Dec 21 '17 at 16:02
  • @KevinCook - If you look at the edit time that it was added it is before your comment :) And besides as OP didn't say in which environment we should strive to use the latest versions – Gilad Green Dec 21 '17 at 16:18
  • Ok, looks good. In the meantime, I went another route but I'll accept the answer so it'll help others. – frenchie Dec 21 '17 at 17:26
  • "Looking at the edit time" doesn't matter, since when I had refreshed, attempted to use your broken code, and then replied to what I was looking at on my screen, you had fixed it from the previous edit... :P As far as using the latest and greatest, in most environments you'll find that companies don't upgrade instantly and making the code work for a greater number of users can be beneficial. – Kevin Cook Dec 21 '17 at 17:45
1
int x;
var TheListOfInts = s.TheListOfStrings.Split(',').Select(g => Int32.TryParse(g, out x) ? x : 0).ToList();

Use tryparse, and catch whether g is a valid integer and you can set a default if not. (I put the default to 0);

Kevin Cook
  • 1,922
  • 1
  • 15
  • 16
  • 1
    The first `ToList()` isn't needed and you can use `out int x` instead of declaring it separately. (I suspect the latter might depend on which version of C# is in use.) – Andrew Morton Dec 21 '17 at 15:46
  • he had it that way in his code, I just edited out the convert to a tryparse. *shrug* – Kevin Cook Dec 21 '17 at 15:50
  • It works properly as it is, hence my +1, but sometimes it is nice to add little improvements to an OP's code so that they can learn extra bits :) – Andrew Morton Dec 21 '17 at 15:51
  • Re: `out int x` - which version of VS are you using? I tried it in VS2017. – Andrew Morton Dec 21 '17 at 15:52
  • I'm running it in vs2015 – Kevin Cook Dec 21 '17 at 15:53
  • My suspicion was correct - it was just added: [What’s New in C# 7.0](https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/) and the very first item mentioned is out variables. – Andrew Morton Dec 21 '17 at 15:56
  • How will OP be able to tell between a valid value of `0` and a case of a failed parse? – Gilad Green Dec 21 '17 at 15:59
  • he can put a default of some number, -99 for instance... I don't know his business rules... He might need to keep the numbers in order and removed segments can mess things up as well... – Kevin Cook Dec 21 '17 at 16:06
  • The only thing I would say is that being these are integers, the OP should be retrieving an enumeration of `nullable` and the default should be `null` as `0` *is* a valid integer. – JuanR Dec 21 '17 at 16:29