Nick Allen
Nick Allen

Reputation: 12220

How to create a List<T> from a comma separated string?

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));
    }
}

Upvotes: 17

Views: 41809

Answers (6)

Konrad Rudolph
Konrad Rudolph

Reputation: 545618

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.

Upvotes: 4

Jason
Jason

Reputation: 28600

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).

Upvotes: 50

Ronald Wildenberg
Ronald Wildenberg

Reputation: 32104

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.

Upvotes: 8

Ruben Bartelink
Ruben Bartelink

Reputation: 61795

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();

Upvotes: 3

kastermester
kastermester

Reputation: 3064

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.

Upvotes: 2

Dario
Dario

Reputation: 49218

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();

Upvotes: 3

Related Questions