6

If I have for example the following string:

"123;3344;4334;12"

and I want these numbers in a generic List<int>, I guess I don't know of a good way here other than to split in a loop and do a conversion then add to a List<int> through each iteration. Does anyone have other ways to go about this?

Updated. Here's what I came up with. I want to do this the old fashion way, not with LINQ because I'm trying to get better with just strings, arrays, lists and manipulating and converting in general.

public List<int> StringToList(string stringToSplit, char splitDelimiter) { List<int> list = new List<int>(); if (string.IsNullOrEmpty(stringToSplit)) return list; string[] values = stringToSplit.Split(splitDelimiter); if (values.Length <= 1) return list; foreach (string s in values) { int i; if (Int32.TryParse(s, out i)) list.Add(i); } return list; } 

This is a new string utility method I plan on using whenever I need to convert a delimited string list to List

So I'm returning an empty list back to the caller if something fails. Good/Bad? is it pretty common to do this?

Yes, there are more "elegant" ways to do this with LINQ but I want to do it manually..the old way for now just for my own understanding.

Also, what bothers me about this:

list.AddRange(str.Split(';').Select(Int32.Parse)); 

is that I have no idea:

  1. How to shove in a TryParse there instead.
  2. What if the str.Split(';').Select(Int32.Parse) just fails for whatever reason...then the method that this AddRange resides in is going to blow up and unless I add a try/catch around this whole thing, I'm screwed if I don't handle it properly.
1

5 Answers 5

6
static int? ToInt32OrNull(string s) { int value; return (Int32.TryParse(s, out value)) ? value : default(int?); } // ... var str = "123;3344;4334;12"; var list = new List<int>(); list.AddRange(str.Split(';') .Select(ToInt32OrNull) .Where(i => i != null) .Cast<int>()); 

Questioner notes:

I don't know of a good way here other than to split in a loop and do a conversion then add to a List

In general, this is a major reason why LINQ was brought into C# - to remove the need to work with sequences of values by implementing loops, and instead just declare your intention to transform the sequence. If you ever find yourself thinking "I don't know how to do this except with a loop" - it's time to look into a LINQ construct which will do the work for you.

Performance Update:

Performance of LINQ has been quesioned below. While in the comments the idea of LINQ being slower is defended since we gain the benefits of readability, maintainability and composibility, there is another aspect which gives LINQ an easy performance advantage: parallelism. Here is an example where adding just one extension method call, AsParallel() doubles the performance. This is a great example of where scale-out beats micro-optimization without even needing to measure very carefully. Note I'm not claiming that micro-optimizations are not ever needed, but with the tools we have available at this level of absraction, the need becomes vanishingly small.

class Program { private const int ElementCount = 10000000; static void Main(string[] args) { var str = generateString(); var stopwatch = new Stopwatch(); var list1 = new List<int>(ElementCount); var list2 = new List<int>(ElementCount); var split = str.Split(';'); stopwatch.Start(); list1.AddRange(split .Select(ToInt32OrNull) .Where(i => i != null) .Cast<int>()); stopwatch.Stop(); TimeSpan nonParallel = stopwatch.Elapsed; stopwatch.Restart(); list2.AddRange(split .AsParallel() .Select(ToInt32OrNull) .Where(i => i != null) .Cast<int>()); stopwatch.Stop(); TimeSpan parallel = stopwatch.Elapsed; Debug.WriteLine("Non-parallel: {0}", nonParallel); Debug.WriteLine("Parallel: {0}", parallel); } private static String generateString() { var builder = new StringBuilder(1048576); var rnd = new Random(); for (int i = 0; i < ElementCount; i++) { builder.Append(rnd.Next(99999)); builder.Append(';'); } builder.Length--; return builder.ToString(); } static int? ToInt32OrNull(string s) { int value; return (Int32.TryParse(s, out value)) ? value : default(int?); } } 

Non-parallel: 00:00:07.0719911

Parallel: 00:00:04.5933906

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

19 Comments

yea I wonder on performance vs. the standard split in a loop though
@coffeeaddict: It's almost always negligable, and it should only be considered for change if it is measured and found to be a problem. Here's a good, recent comparison: jerrytech.blogspot.com/2010/02/…
You're a pretty lucky programmer if youre biggest performance concern is a string split function. I don't believe LINQ has any significant overhead over foreach loops, it's just easy for naive programmers to lose track of their big O complexity when they don't see nesting.
@coffeeaddict, I disagree entirely with your position on optimization, as I'm sure most other developers would. Sure, performance might be everything, but guessing where the performance hit will be should NOT be done up front, and you'll invariably get it wrong, ending up with opaque code that could be much clearer. Design well, code clearly, then only optimize when a problem shows up.
@coffeeaddict: sorry, but I disagree. Even at that scale, code readability and maintainability trump milliseconds, especially when it is so cheap to scale out.
|
5
string str = "123;3344;4334;12"; List<int> list = new List<int>(); foreach (string s in str.Split(';')) { list.Add( Int32.Parse(s)); } 

6 Comments

+1, you read the title! I would suggest using TryParse instead of Parse.
I wounder if you can just do List<int> list = "123;3344;4334;12".Split(";"); I know you can with an array: string[] list = "123;3344;4334;12".Split(";");
@coffee, no. You can't implicitly convert from an array of strings to a List<int>. Also, it should be Split(';'). Note the single quote, because it's a character literal.
So if TryParse fails, then null is added? If you've got list.Add(tryparse...) and the parse fails is something still added to the list?
@coffeeaddict, you can't do list.Add(int.TryParse... when working with a list of ints because TryParse returns a bool. If it fails, null does not get added, false does (and true on success).
|
3
List<int> list = (from numString in "123;3344;4334;12".Split(';') select int.Parse(numString)).ToList(); 

Comments

1
string myString = "123;3344;4334;12"; var ints = new List<int>(); (from s in myString.Split(';') select int.Parse()).ToList().ForEach(i=>ints.Add(i)); 

I've heard .Net 4.0 may have added ForEach to Enumerable<T>, so the ToList might be unnecessary there (can't test).

2 Comments

After the ToList, you have a list of ints. The ForEach is unneeded.
@Matthew Flaschen, agreed. My initial (and admittedly hurried) initial thought was the list might not be original and the contents might need to be preserved. i.e. append the results to an existing list without replacement.
-1

I think this is simplest

 var str = "123;3344;4334;12"; var list = str.Split(';').ToList().Cast<int>(); 

1 Comment

-1: This never works, cause you can't cast a string to an integer. You can only parse it (using int.Parse() or int.TryParse()).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.