var duckerBrothers = new List<string> { "Andy", "Mike", "Hugh" };
var output = string.Empty;
foreach (var duckerBrother in duckerBrothers)
{
if (output != string.Empty)
{
output += ", ";
}
output += duckerBrother;
}
Can be rewritten as:
var duckerBrothers = new List<string> { "Andy", "Mike", "Hugh" };
var output = string.Join(",", duckerBrothers);
That's what I get for assuming that there is no built-in way of doing things.
Original post on Dreamwidth - there are
2013-01-15 03:31 pm (UTC)
I'll say this for PHP, it has lots of helpful things. (Just they're all inconsistently named and parametrized...)
2013-01-15 03:46 pm (UTC)
2013-01-15 06:46 pm (UTC)
// WTF, PHP?
;)
2013-01-15 04:04 pm (UTC)
2013-01-15 03:33 pm (UTC)
Edited at 2013-01-15 03:35 pm (UTC)
2013-01-15 04:05 pm (UTC)
2013-01-15 03:58 pm (UTC)
When I become world dictator, I'll have it re-written. Just you wait!
2013-01-15 04:04 pm (UTC)
In fact, earlier versions of string.Join only took arrays of strings - allowing any Ienumerable<string> is a modern addition.
2013-01-15 04:06 pm (UTC)
I think everybody is better off with me not being an API- or library-designer. :P
2013-01-15 04:18 pm (UTC)
In C# 4 you could use an extension method on IEnumerable to do that - but the code long-predates that.
2013-01-15 10:07 pm (UTC)
2013-01-15 10:10 pm (UTC)
2013-01-15 10:52 pm (UTC)
2013-01-15 10:07 pm (UTC)
Better to adopt a Scheme-like approach and use a higher order function (reduce) to apply a function that concatenates a pair of strings (with a delimiter) to a list of strings.
2013-01-15 10:09 pm (UTC)
var result = duckerBrothers.Aggregate((collected, next) => collected + ", " + next);
is more complex and harder to understand than:
var result = string.Join(",", duckerBrothers);
The latter is instantly clear as to what it does, and probably a lot faster than the former.
2013-01-16 09:30 am (UTC)
I'd wrap it up like
public static string MyJoinAsStrings<T>(this IEnumerable<T> items) { return items .Select(x => x.ToString()) .Aggregate((collected, next) => collected + ", " + next); }But of course with the caveats that
1) There is something built in for the usual case where T is already string, and
2) joining strings with "+" is not suitable for long lists.
Edited at 2013-01-16 09:33 am (UTC)
2013-01-16 10:21 am (UTC)
public static string MyJoinAsString(this IEnumerable items) { return string.Join(", ", items.Select(item => item.ToString())); }And then you don't have to worry about long lists, because Join is optimised for that. Oh, and String.ToString() is just a "return this", which has negligible overhead, so I'm not worried enough about that to write a specific override.
2013-01-16 01:13 pm (UTC)
2013-01-15 04:07 pm (UTC)
Are there languages that have some nice syntax for that?
2013-01-15 04:16 pm (UTC)
I'm sure there are languages with lovely constructs for this kind of thing. People seem to like Python a lot.
2013-01-15 05:57 pm (UTC)
As to the general case, the pattern known as 'fold' (or 'reduce' in python) in functional languages elegantly encapsulates it:
http://en.wikipedia.org/wiki/Fold_(high
2013-01-15 07:00 pm (UTC)
joinfunctions - in Perl's case it's a built-in function, and in Ruby's case it's a method on Array. There's a Haskelljoinfunction (which works on arbitrary lists) in Data.List.Utils, but as you point out it's easy enough to write one as a fold: Note that I'm using a right fold rather than a left fold; if I'd used foldl1, it would take quadratic time (as would Andy's hand-rolled C# version, assuming C# strings are wrappers around null-terminated C strings). This is why one should always use the built-injoinoperator in scripting languages - they typically run in linear time, whereas naive hand-rolled versions would run in quadratic time. The Haskell version ofjoinin Data.List.Utils is defined as using theintersperseoperator defined in Data.List. Which I think should run in linear time, but I'm having a really hard time thinking about its time and space behaviour - there's a reason I'm not a Haskell programmer!Edited at 2013-01-15 07:02 pm (UTC)
2013-01-15 10:02 pm (UTC)
var duckerBrothers = new List {"Andy", "Mike", "Hugh"};
var result = duckerBrothers.Aggregate((collected, next) => collected + ", " + next);
gives me "Andy, Mike, Hugh".
2013-01-15 10:06 pm (UTC)
2013-01-15 10:01 pm (UTC)
var duckerBrothers = new List {"Andy", "Mike", "Hugh"};
var result = duckerBrothers.Aggregate((collected, next) => collected + ", " + next);
gives me "Andy, Mike, Hugh".
2013-01-15 10:55 pm (UTC)
And, your first method is just crying out to be re-written using a StringBuilder for cases where the list can be long and perf matters.
Edited at 2013-01-15 10:56 pm (UTC)
2013-01-16 10:23 am (UTC)
2013-01-16 04:35 pm (UTC)
and yes, i live in PHP or occasionally shell scripts. :)
2013-01-16 06:29 pm (UTC)
2013-01-17 01:15 pm (UTC)
- the convoluted ways of having arrays/lists/collections/etc of things and them all being subtly different and not interchangeable, as opposed to PHP's powerful arrays you can bung anything into.
- little things like above string.empty and string.join
- i can never get my head round how to represent things i'm doing as a set of classes, or if i can it seems really contrived (like having classes purely to serve OO mentality rather than representing anything meaningful) and much harder to read/debug and/or less efficient than "my way".
2013-01-17 01:35 pm (UTC)
I can have an array of objects if I want, and put anything I want into it. But then whoever is writing that part of the application might put things into it I wasn't expecting, and then we'd be debugging all sorts of awfulness.
I don't have to use string.empty - I can just use "". But I've gotten into the habit, because it avoids creating a new string.
string.join is just a function. It's got to go _somewhere_ and there are millions of functions in the base libraries, so organising them by the type of object you're working with makes sense. You can think of it like a filing system (which, in many ways, it is).
None of this is useful for a small language doing a limited number of things in a small project. It's only really useful when you're talking about large projects doing complex stuff.