17

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));
    }
}
5
  • 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... Commented May 26, 2009 at 11:11
  • 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 Commented May 26, 2009 at 11:18
  • Yes, that's exactly what I was hinting at... Commented May 26, 2009 at 11:41
  • 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. Commented Mar 6, 2013 at 23:06
  • For more generic conversion stackoverflow.com/questions/28233115/… Commented Jan 30, 2015 at 11:01

6 Answers 6

50

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

Sign up to request clarification or add additional context in comments.

5 Comments

I've edited my answer to reflect what's needed for an inline TryParse implementation. This is where a Convert.ToNullableInt32 implementation would be helpful :)
Yous sure that compiles (in LINQPad :D)
Yes. The only thing I'm not 100% sure on is the order of operations in the property initializer ('out temp' followed by I = temp). I believe that's guaranteed to be executed in order.
Agree it should work from exec order POV, but I hate temps shared by stuff further down like this. Extension/helper method is way to go thide all this cruft.
From a comment at this almost-duplicate Q&A stackoverflow.com/a/911729/292060, the Select(i => int.Parse(i)) portion can be simplified to Select(int.Parse)
8

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.

2 Comments

Well then, same comment re not using TryParse :P (But undoing -1!)
Yes, TryParse was not included and since the data is a query string it should be there. But thanks for undoing the -1 :)
4

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.

9 Comments

This way you get a list of booleans. Int32.TryParse returns a boolean.
Another issue with the last 2 examples is actually that they return IEnumerable<T>
@Konrad, I jumped in and fixed that for you. Hope you don't mind ;)
careful, TryParse is needed here
@Ruben, I've rolled back to Konrad's original answer, but I'm not really sure if that's preferable or not. Using TryParse means the code won't compile, using Parse means it'll compile but will cause an exception if/when it hits a bad ID at runtime.
|
3

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

Comments

3

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

1 Comment

With inline declaration the part with Select could be slightly simpler .Select(s => int.TryParse(s, out int d)? (int?)d : null)
2

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.

3 Comments

Regex isnt saying [1-9]+, but if it did, it could still be out of range and throw - not same as tryparse.
About out of range - very true. However, I don't see why you want to change the Regex to [1-9]+, this would turn the number "10" into an invalid number. Also I will modify the regex slightly to take into account of negative numbers.
Sorry, meant [0-9], (really I meant \d). Was only making the "two problems" allegation, together with pointing out that the code is more complex and differnet with regex. Your regex still doesnt have a "+" after the [0-9] so will only work with 1 digit and hence never get out of raqnge :P

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.