Ok, so I wanted to name the title of this post “Simple One Line String Concatenation with Lambda“, but that didn’t happen when I found a few holes in my approach if you wish to omit your concatenation string from being shown at the end (most cases, like with comma-delimited lists). So, I have offered a solution for both situations, one quite simple when you just wish to concatenate two or more strings, and one more advanced which leaves off your concatenation at the end.
So let’s get started, supposing you wish to compile a list of song titles separated by a comma, ordinarily you would for each loop them, then assign the comma as “, “ on the second iteration.
Well, I wanted to get tricky of course, I thought I could get this going as a one-liner, and well, I did, but this one does not remove the trailing “, “ at the end, so you would effectively end up with “Bob Marley, Chase & Styles, DJ Qbert, “, obviously being undesirable. So here it is:
LAMBDA CONCATENATION (INCLUDES TRAILING DELIMITER):
string songTitles = null; titles.ForEach(x => songTitles += x.Name + ", ");
However now with a bit of tinkering and learning quite a bit about Lambda’s just by working with Intellisense I managed to put together this bad dog, hey I know it’s not one-line, but we can call it one statement. it was more an exercise in theory, and I hope you find it useful.
LAMBDA CONCATENATION (EXCLUDES TRAILING DELIMITER):
string songTitles = null;
titles
.Select((x, i) => new
{
Item = x,
Index = i + 1,
Length = titles.Count
})
.ToList()
.ForEach(
x => songTitles += x.Item.Name + (x.Index < x.Length ? ", " : null));
This will now return the desired result of "Bob Marley, Chase & Styles, DJ Qbert" without the trailing comma.
With both examples, "titles" being your Collection, "songTitles" being the string you wish to build with a comma, "x.Item.Name" being the item you wish to build into your string, and ", " being the concatenation string you wish to use.
The benefit and the real reason I wanted to create a lambda for this to work off a type deriving from List was so I did not need to create a string[] array for which string.Join() requires or, as I said perform a multiple line for each statement to compose this.
It should work on any Generic List type or object derived from IEnumerable.
Sorry folks, it's even easier than that, I don't know WHAT I was thinking not using string.Join(), I did experience a problem, but as a commenter, Luke pointed out string.Join() is achievable by using "Select".
string songTitles = string.Join(",", titles.Select(x => t.Item.Name).ToArray());Or for another very elegant method, check out Mark's use of the "Aggregate" method:
string songtitles = titles.Select(s=>s.Name).Aggregate((a, b) => a + "," + b);Both a lot simpler than mine *sob*. Embarassment. Oh well, mine was a Lambda tech demo I guess.
4 Comments
Or you could use Aggregate
string songtitles=titles.Select(s=>s.Name).Aggregate((a, b) => a + “,” + b);
Are you serious??
Blast! There’s always another method you just didn’t realise..
This just shows that everyone should read back to front on all the extension methods, including myself. My friend even did a good post on it http://www.bleevo.com/2009/02/system-linq-enumerable-aggregate-better-know-an-extension-method-part-1/.
Not sure why you’re avoiding string.Join(). This seems way easier:
string songTitles = string.Join(“,”, titles.Select(x => t.Item.Name).ToArray());
I just came across your blog entry, great entry, great feedback, and I thought I’d point out that the aggregate function throws an exception “Sequence contains no elements” if the list has no items, whereas the join does not. So, there’s definitely a functional (no pun intended) difference between the two approaches.
Post a Comment