Reputation: 12220
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
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
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
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
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
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
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