views:

1503

answers:

14

Let's say I have a web page that currently accepts a single ID value via a url parameter:
http://example.com/maypage.aspx?ID=1234

I want to change it to accept a list of ids, like this:
http://example.com/mypage.aspx?IDs=1234,4321,6789

So it's available to my code as a string via context.Request.QueryString["IDs"]. What's the best way to turn that string value into a List<int>?

Edit: I know how to do .split() on a comma to get a list of strings, but I ask because I don't know how to easily convert that string list to an in list. This is still in .Net 2.0, so no lambdas.

A: 

You can use string.Split() to split the values once you have extracted them from the URL.

string[] splitIds = ids.split(',');
Groky
+2  A: 

All I can think of is to loop over the list of strings (which you have got from performing a split) and doing something like int.TryParse() on them one after the other and putting them into a new List<int>. Encapsulate it in a nice little helper method somewhere and it won't be too horrid.

Splash
A: 

You'll just have to foreach through them and int.TryParse each one of them. after that just add to the list.

Nevermind - @Splash beat me to it

sirrocco
+1  A: 

You can instantiate a List<T> from an array.

VB.NET:

Dim lstIDs as new List(of Integer)(ids.split(','))

This is prone to casting errors though if the array contains non-int elements

The problem with this is that just one casting error kills the entire list, but I still up-voted it, and maybe that's the behavior I should go for.
Joel Coehoorn
A: 

split is the first thing that comes to mind, but that returns an array, not a List; you could try something like:


List<int> intList = new List<int>;

foreach (string tempString in ids.split(',')
{
    intList.add (convert.int32(tempString));
}

RichieACC
+5  A: 

Something like this might work:

public static IList<int> GetIdListFromString(string idList)
{
    string[] values = idList.Split(',');

    List<int> ids = new List<int>(values.Length);

    foreach (string s in values)
    {
     int i;

     if (int.TryParse(s, out i))
     {
      ids.Add(i);
     }
    }

    return ids;
}

Which would then be used:

string intString = "1234,4321,6789";

IList<int> list = GetIdListFromString(intString);

foreach (int i in list)
{
    Console.WriteLine(i);
}
Sarcastic
Nice, I was just about to post the exact same answer :(
Huppie
A: 
List<int> convertIDs = new List<int>;
string[] splitIds = ids.split(',');
foreach(string s in splitIds)
{
    convertIDs.Add(int.Parse(s));
}

For completeness you will want to put try/catches around the for loop (or around the int.Parse() call) and handle the error based on your requirements. You can also do a tryparse() like so:

List<int> convertIDs = new List<int>;
string[] splitIds = ids.split(',');
foreach(string s in splitIds)
{
    int i;
    int.TryParse(out i);
    if (i != 0)
       convertIDs.Add(i);
}
dpollock
A: 

To continue on previous answer, quite simply iterating through the array returned by Split and converting to a new array of ints. This sample below in C#:

        string[] splitIds = stringIds.Split(',');

        int[] ids = new int[splitIds.Length];
        for (int i = 0; i < ids.Length; i++) {
            ids[i] = Int32.Parse(splitIds[i]);
        }
Philibert Perusse
+1  A: 

This will only work in .NET 3.5


List<int> myList = new List<int>(Request.QueryString["ids"].Split(new char[] {','}).Cast<int>());
Chris
No way dude, you can't cast a string to an integer, it doesn't work that way. You'll have to add parsing to it. Select(x => int.Parse(x)) that could still fail though, if a single value is not a valid Int32 string representation.
John Leidegren
A: 

If you like the functional style, you can try something like

    string ids = "1,2,3,4,5";

    List<int> l = new List<int>(Array.ConvertAll(
        ids.Split(','), new Converter<string, int>(int.Parse)));

No lambdas, but you do have Converters and Predicates and other nice things that can be made from methods.

Jesse Millikan
A: 

I think the easiest way is to split as shown before, and then loop through the values and try to convert to int.

class Program
{
    static void Main(string[] args)
    {
        string queryString = "1234,4321,6789";

        int[] ids = ConvertCommaSeparatedStringToIntArray(queryString);
    }

    private static int[] ConvertCommaSeparatedStringToIntArray(string csString)
    {
        //splitting string to substrings
        string[] idStrings = csString.Split(',');

        //initializing int-array of same length
        int[] ids = new int[idStrings.Length];

        //looping all substrings
        for (int i = 0; i < idStrings.Length; i++)
        {
            string idString = idStrings[i];

            //trying to convert one substring to int
            int id;
            if (!int.TryParse(idString, out id))
                throw new FormatException(String.Format("Query string contained malformed id '{0}'", idString));

            //writing value back to the int-array
            ids[i] = id;
        }

        return ids;
    }
}
Magnus Akselvoll
+8  A: 

No offense to those who provided clear answers, but many people seem to be answering your question instead of addressing your problem. You want multiple IDs, so you think you could this this:

http://example.com/mypage.aspx?IDs=1234,4321,6789

The problem is that this is a non-robust solution. In the future, if you want multiple values, what do you do if they have commas? A better solution (and this is perfectly valid in a query string), is to use multiple parameters with the same name:

http://example.com/mypage.aspx?ID=1234;ID=4321;ID=6789

Then, whatever query string parser you use should be able to return a list of IDs. If it can't handle this (and also handle semi-colons instead of ampersands), then it's broken.

Ovid
Robert Paulson
Because, as stated, if the *values* are allowed to contain commas, splitting on commas is problematic. The CGI protocol allows multiple parameters of the same name, so the entire "can I split on commas or not" question becomes moot. That's what duplicate parameter names are for.
Ovid
teach a man to fish...
Andrew Theken
+1  A: 

Final code snippet that takes what I hope is the best from all the suggestions:

Function GetIDs(ByVal IDList As String) As List(Of Integer)
    Dim SplitIDs() As String = IDList.Split(new Char() {","c}, StringSplitOptions.RemoveEmptyEntries)
    GetIDs = new List(Of Integer)(SplitIDs.Length)
    Dim CurID As Integer
    For Each id As String In SplitIDs
        If Integer.TryParse(id, CurID) Then GetIDs.Add(CurID)
    Next id
End Function

I was hoping to be able to do it in one or two lines of code inline. One line to create the string array and hopefully find something in the framework I didn't already know to handle importing it to a List<int> that could handle the cast intelligently. But if I must move it to a method then I will. And yes, I'm using VB. I just prefer C# for asking questions because they'll get a larger audience and I'm just about as fluent.

Joel Coehoorn
+1  A: 

I see my answer came rather late, i.e. several other had written the same. Therefore I present an alternative method using regular expressions to validate and divide the string.

class Program
{
    //Accepts one or more groups of one or more digits, separated by commas.
    private static readonly Regex CSStringPattern = new Regex(@"^(\d+,?)*\d+$");

    //A single ID inside the string. Must only be used after validation
    private static readonly Regex SingleIdPattern = new Regex(@"\d+");

    static void Main(string[] args)
    {
        string queryString = "1234,4321,6789";

        int[] ids = ConvertCommaSeparatedStringToIntArray(queryString);
    }

    private static int[] ConvertCommaSeparatedStringToIntArray(string csString)
    {
        if (!CSStringPattern.IsMatch(csString))
            throw new FormatException(string.Format("Invalid comma separated string '{0}'",
                                                    csString));

        List<int> ids = new List<int>();
        foreach (Match match in SingleIdPattern.Matches(csString))
        {
            ids.Add(int.Parse(match.Value)); //No need to TryParse since string has been validated
        }
        return ids.ToArray();
    }
}
Magnus Akselvoll