16
votes

Given the variable

string ids = Request.QueryString["ids"]; // "1,2,3,4,5";

Is there any way to convert it into a List without doing something like

List<int> myList = new List<int>();

foreach (string id in ids.Split(','))
{
    if (int.TryParse(id))
    {
        myList.Add(Convert.ToInt32(id));
    }
}
6
Can you specify the behaviour you want please - is it just as above, i.e., silently ignore bits that are not Int32s? None of the answers are taking that into account... - Ruben Bartelink
I am silently ignoring bad ids because they are entered by content editors who want to pull in certain images on to their pages, however I can put validation on the field to stop that from happening I suppose - Nick Allen
Yes, that's exactly what I was hinting at... - Ruben Bartelink
This almost-duplicate stackoverflow.com/questions/911717/…, from 6 hours later, specifically asks for a string of numbers, so it has the one simple answer. - goodeye
For more generic conversion stackoverflow.com/questions/28233115/… - Gopi

6 Answers

50
votes

To create the list from scratch, use LINQ:

ids.Split(',').Select(i => int.Parse(i)).ToList();

If you already have the list object, omit the ToList() call and use AddRange:

myList.AddRange(ids.Split(',').Select(i => int.Parse(i)));

If some entries in the string may not be integers, you can use TryParse:

int temp;
var myList = ids.Split(',')
    .Select(s => new { P = int.TryParse(s, out temp), I = temp })
    .Where(x => x.P)
    .Select(x => x.I)
    .ToList();

One final (slower) method that avoids temps/TryParse but skips invalid entries is to use Regex:

var myList = Regex.Matches(ids, "[0-9]+").Cast<Match>().SelectMany(m => m.Groups.Cast<Group>()).Select(g => int.Parse(g.Value));

However, this can throw if one of your entries overflows int (999999999999).

8
votes

This should do the trick:

myList.Split(',').Select(s => Convert.ToInt32(s)).ToList();

If the list may contain other data besides integers, a TryParse call should be included. See the accepted answer.

4
votes

Using Linq:

myList.AddRange(ids.Split(',').Select(s => int.Parse(s));

Or directly:

var myList = ids.Split(',').Select(s => int.Parse(s));

Also, to prevent the compiler from explicitly generating the (largely redundant) lambda, consider:

var myList = ids.Split(',').Select((Func<string, int>)int.Parse);

(Hint: micro-optimization.)

There's also TryParse which should be used instead of Parse (only) if invalid input is possible and should be handled silently. However, others have posted solutions using TryParse so I certainly won't. Just bear in mind that you shouldn't duplicate the calculation.

3
votes

Or including TryParse like in your example:

var res = ids.Split(',').Where(x => { int tmp; return int.TryParse(x, out tmp); }).Select(x => int.Parse(x)).ToList();
3
votes

To match the request in terms of performance characteristics and behaviour, it should do the same thing and not go off doign regexes or not doing the 'TryParse':-

ds.Split(',')
  .Select( i => {
    int value; 
    bool valid = int.TryParse(out value); 
    return new {valid, value}
  })
  .Where(r=>r.valid)
  .Select(r=>r.value)
  .ToList();

But while correct, that's quite ugly :D

Borrowing from a hint in Jason's comment:-

ds.Split(',')
  .Select( i => {
    int value; 
    bool valid = int.TryParse(out value); 
    return valid ? new int?( value) : null;
  })
  .Where(r=>r != null)
  .Select(r=>r.Value)
  .ToList();

Or

static class Convert
{
  public static Int32? ConvertNullable(this string s)
  {
    int value; 
    bool valid = int.TryParse(out value); 
    return valid ? new int?( value) : null;
  }
}

ds.Split(',')
  .Select( s => Convert.ConvertNullable(s))
  .Where(r=>r != null)
  .Select(r=>r.Value)
  .ToList();
2
votes

One issue at hand here is how we're gonna deal with values that are not integers (lets assume we'll get some that is not integers). One idea might be to simply use a regex:

^-?[0-9]+$

Now, we could combine all this up with (as shown in Konrad's example):

var myList = ids.Split(',').Where(s => Regex.IsMatch(s, "^-?[0-9]$")).Select(s => Convert.ToInt32(s)).ToList();

That should do the job.