Say you want to search a string with a regular expression and return all the matches concatenated together, using LINQ:
var str = "some string";
var matches = Regex.Matches(str, @"REGEX");
Three ways to concatenate:
Using String.Join (simplest):
var foo = String.Join("", (from Match match in result select match.Value).ToArray());
Using an accumulator:
var foo = (from Match match in matches select match.Value)
.Aggregate(new StringBuilder(), (sb, s) => sb.Append(s)).ToString();
Using a loop:
var sb = new StringBuilder();
foreach (var s in (from Match match in result select match.Value)){
sb.Append(s);
}
var foo = sb.ToString();
First seems most concise, and it's easier to specify a join character with. Apparently there's no way to massage an IEnumerable(T) into a String.Join, so unfortunately you need to pass it an array, which makes the IEnumerable fill out all its values into an array (so it can't be lazy), and then String.Join makes another pass over that array and copies the values into a string. So it uses double the space and double the time.
The second is more obscure, but only makes one pass over the result, though it's harder to specify a join character if desired.
The third is presumably most efficient, but it's more verbose.
In conclusion, there should be a String.Join(IEnumerable<T>).
Edit: Though it's impossible to define a "static" extension method (like, another variation of String.Join), you can define a Join method on IEnumerable like so:
static class Extentions{
public static string Join(this IEnumerable source, string separator){
var sb = new StringBuilder();
bool first = true;
foreach(var foo in source){
if(!first)
sb.Append(separator);
sb.Append(foo.ToString());
first = false;
}
return sb.ToString();
}
}
The first example above now becomes:
var foo = (from Match match in result select match.Value).Join("");
or even more concisely:
var foo = Regex.Matches(str, @"REGEX").Join("");
// (apparently the ToString on a Match object returns its Value)
Very cool.
Note: Works with custom ToString()s as expected:
class Custom{
public string Value { get; set; }
public override string ToString(){
return "VALUE: "+Value;
}
}
var list = new List<Custom> {
new Custom { Value = "one" },
new Custom { Value = "two" }
};
Console.WriteLine(list.Join(", "));
prints "VALUE: one, VALUE: two" as expected.
Final note: I would have used FirstOrDefault in my Join extension method instead of a first boolean, but the example of the regular expression object was chosen because it's not a generic, so I can't use IEnumerable<T>, only IEnumerable.
new⇒I hate ASP.NET
CF, why pick that piece of trash?Cold Confusion. Is it finallyreally a OO...
ColdConfusion: Sep 5, 8:36pm