views:

501

answers:

5

I have some LINQ code that generates a list of strings, like this:

var data = from a in someOtherList
           orderby a
           select FunctionThatReturnsString(a);

How do I convert that list of strings into one big concatenated string? Let's say that data has these entries:

"Some "
"resulting "
"data here."

I should end up with one string that looks like this:

"Some resulting data here."

How can I do this quickly? I thought about this:

StringBuilder sb = new StringBuilder();
data.ToList().ForEach(s => sb.Append(s));
string result = sb.ToString();

But that just doesn't seem right. If it is the right solution, how would I go about turning this into an extension method?

+8  A: 

Have you tried String.Join? If you're already willing to take the overhead of a .ToList call then instead use .ToArray() and combine it with a call to String.Join.

var joined = String.Concat(someQuery.ToArray());

Note: My solution is likely not the fastest as it involves a bit of overhead in the array. My suspicion is that it would be faster to go more Marc's route. But in most cases if you're just looking for the quick and dirty way to do it in code, my route will work.

JaredPar
Any particular reason not to use `string.Concat`?
Mehrdad Afshari
@Mehrdad, nope, Join was just the first one that popped into my head today.
JaredPar
In my tests performance is neck-and-neck with Marc's solution (for a wide variety of string and collection lengths), so you get my vote.
LukeH
+10  A: 

How about:

public static string Concat(this IEnumerable<string> source) {
    StringBuilder sb = new StringBuilder();
    foreach(string s in source) {
        sb.Append(s);
    }
    return sb.ToString();
}

and:

string s = data.Concat();

This then has no need for the extra ToList() / ToArray() step.

Marc Gravell
+1 This is not the shortest method, but the OP is clearly asking for the *fastest*, and this indeed beats using `ToArray()` following by `string.Concat`/`string.Join`.
Noldorin
@Noldorin: Fastest is a bit undefined ;) For programmer or machine?
Mehrdad Afshari
Thanks! By fastest I did mean for running time.
jasonh
Minor change: There's already a Concat extension method provided my MS, so I had to name it ConcatString.
jasonh
@jasonh: If speed is the issue, it's faster to take two passes at the list, the first time to calculate the total length so that the StringBuilder can be preallocated.
Steven Sudit
@jasonh: Renaming is not strictly required (though it might be better in terms of readability) as the MS provided method takes a parameter.
Mehrdad Afshari
@Steven Sudit: In that case, you would have just used `String.Concat`. The problem is, you are dealing with an `IEnumerable<T>` which you don't know the size of either (and you have to store item references somewhere for reuse).
Mehrdad Afshari
@Mehrdad: So does Marc's code. I put his in and I got a compiler error and IntelliSense took me to the metadata for the MS version, so the compiler was definitely trying to go for the MS version.
jasonh
@jasonh: I just tested it and it worked as I expected. The cause of your problem is something else. Marc code takes a single parameter which will become implicit as it's an extension method but MS version takes 2 parameters (one of which is passed implicitly). They can happily live together.
Mehrdad Afshari
A: 

Use "Aggregate" like this:

 List<string> strings = new List<string>() {"bob", "steve", "jane"};
 string result = strings.Aggregate((working, next) => working + next);
 Console.WriteLine(result);

Note: Aggregate is in the System.Linq namespace as an extension method.

Mike
That could be a ***lot*** of intermediate strings...
Marc Gravell
A: 

Depending on how the JIT optimizes it, either string.Concat() or Marc's method with StringBuilder could be faster. Since you're using Linq here, I'll assume performance isn't the absolute #1 requirement, in which case I'd go with the easiest to read:

string.Concat(data.ToArray());

Edit: if and only if data is IEnumerable of a value type, you'll need to cast it to an IEnumerable<object>:

string.Concat(data.Cast<object>().ToArray())

Edit 2: I don't really mean Linq is slow. I only mean that the speed difference between the two ways I mentioned should be extremely minimal if even measurable.

Edit 3: The JIT optimizes almost all operations on the String class, so the single call to the internal runtime of string.Concat really could be faster than using StringBuilder. I'm not sure it is, but you should test it to make sure.

280Z28
Since when Linq has been equivalent to slow?
Mehrdad Afshari
I added edit #2 to clarify, sorry. :)
280Z28
Why would you do `data.Cast<object>()` rather than something like `data.Select(x => x.ToString())`?
LukeH
string has a member string.Concat(object[] args) which very likely performs the internal ToString operations more efficiently. The only reason you'd need to cast to object is value type arrays like int[] cannot be implicitly converted to object[].
280Z28
The `Concat(object[])` overload just calls the standard `ToString` method internally. If you perform the `ToString` operation on the value-types yourself, rather than boxing them with `Cast`, you can then use the `Concat(string[])` overload.
LukeH
A: 
data.ToList().Aggregate(new StringBuilder(), (sb, s) => sb.Append(s)).ToString();
Pavel Minaev