Lets say you have a:
List<string> los = new List<string>();
In this crazy functional world we live in these days which one of these would be best for creating one string by concatenating these:
String.Join(String.Empty, los.ToArray());
StringBuilder builder = new StringBuilder();
los.ForEach(s => builder.Append(s));
string disp = los.Aggregate<string>((a, b) => a + b);
or Plain old StringBuilder foreach
OR is there a better way?
I would go with option A:
String.Join(String.Empty, los.ToArray());
My reasoning is because the Join method was written for that purpose. In fact if you look at Reflector, you'll see that unsafe code was used to really optimize it. The other two also WORK, but I think the Join function was written for this purpose, and I would guess, the most efficient. I could be wrong though...
As per #Nuri YILMAZ without .ToArray(), but this is .NET 4+:
String.Join(String.Empty, los);
string.Concat(los.ToArray());
If you just want to concatenate the strings then use string.Concat() instead of string.Join().
If you use .net 4.0 you can use a sorter way:
String.Join<string>(String.Empty, los);
String.Join() is implemented quite fast, and as you already have a collection of the strings in question, is probably the best choice. Above all, it shouts "I'm joining a list of strings!" Always nice.
los.Aggregate((current, next) => current + "," + next);
My vote is string.Join
No need for lambda evaluations and temporary functions to be created, fewer function calls, less stack pushing and popping.
Related
Trying to determine if it's a better practice to use string.Format in place of concatenating strings and if so, why is this? Also, are their advantages/disadvantages to one or the other that I should be aware of?
This:
string foo = "I" + " am " + " a " + " string.";
or:
string bar = string.Format("{0} am a {1}.", "I", "string");
Obviously oversimplified examples, just wanting to be clear.
The "best practice" should be the thing that makes your code the most readable and maintanable. The performance difference between concatenating strings versus using string.Format versus using a StringBuilder is so small that it's essentially irrelevant.
Assuming the first method was not optimized at compile time, because strings are immutable it will create many intermediate strings. It'll work from left to right so there will first be "I am ", then "I am a ", and finally "I am a string." which is stored in foo.
String.format will not make intermediate strings. To my understanding it does all the manipulation in a char[] which is then made immutable by being made a String.
string rawConnString = Properties.Settings.Default.ConnectionString;
I want to do this with "rawConnString":
rawConnString.Replace("<<DATA_SOURCE>>", server);
rawConnString.Replace("<<INITIAL_CATALOG>>", "tempdb");
Then set the final string to variable finalConnString.
How would I go about doing this?
This is ASP .NET 4.0/C# btw.
string finalString = Properties.Settings.Default.ConnectionString.Replace("<<DATA_SOURCE>>", server).Replace("<<INITIAL_CATALOG>>", "tempdb");
will do it all in one line of code. But it's uglier IMO because you'll have to scroll. The code in your question seems a LOT cleaner and more readable to me.
And doing it in one line of code won't help your performance at all. It should all compile down to the same MSIL either way. I'd leave it as you had it.
Not sure if this is what you're after, but you can chain them:
var finalConnString = rawConnString.Replace("<<DATA_SOURCE>>", server)
.Replace("<<INITIAL_CATALOG>>", "tempdb");
If you're looking to do it with a single method call, I don't think there's anything native to .NET. You can always create an extension method though. Here's a performance-conscious ReplaceMany implementation (signature .ReplaceMany(string[] oldValues, string[] newValues)).
This is frankly trivial; you have 90% of the code you need:
string rawConnString = Properties.Settings.Default.ConnectionString;
string finalConnString = rawConnString
.Replace("<<DATA_SOURCE>>", server)
.Replace("<<INITIAL_CATALOG>>", "tempdb");
To avoid using two back-to-back calls of Replace, you can use regular expressions. However, this is far less readable than the original:
string connString = Regex.Replace(
rawConnString
, "(<<DATA_SOURCE>>)|(<<INITIAL_CATALOG>>)"
, m => m.Groups[1].Success ? server : "tempdb"
);
Link to ideone.
you mean something like this
string tempString=rawConnString.Replace("<<DATA_SOURCE>>", server);
sting finalstring=tempString.Replace("<<INITIAL_CATALOG>>", "tempdb");
First, String.replace does not change the original string: it creates a new string. So you have to assign the return value to something. So the logically simplest thing to do is:
finalstring=rawConnString.Replace("<<DATA_SOURCE>>", server);
finalstring=finalstring.Replace("<<INITIAL_CATALOG>>", "tempdb");
Note that for the second replace, you want to start with the results of the first replace, not the original string.
As String.replace returns a string, and String.replace takes a string, you might find it easier to run them together:
finalstring=rawConnString.Replace("<<DATA_SOURCE>>", server).Replace("<<INITIAL_CATALOG>>", "tempdb");
I am working on a console application, that receives a pretty long list of parameters. For debugging purpose I need to print the parameters passed to a an output file. Right now, I am using the following code to concat command line parameters.
static void Main(string[] args)
{
string Params = string.Empty;
foreach(string arg in args)
{
Params += arg + ",";
}
}
Is there any better way to accomplish this?
What about
Params = string.Join(",", args);
Your foreach approach is not very performant. Since a string is immutable, that means for each iteration of the loop, the string will get thrown away for garbage collection, and a new string will be generated. In the string.Join case, only one string will be generated.
Inside the loop, to get around the same performance, you will have to use a StringBuilder, but in this case it's really no reason not to use string.Join since the code will be much more readable.
You could use this piece of code
String.Join(", ", Environment.GetCommandLineArgs())
You can use String.Join(",",args)
All of the answers here combining the arguments with a single comma will work, but I found that approach lacking somewhat because there's not a clear indicator of "quoted arguments" and those that might contain a comma.
Using the example: Foo.exe an example "is \"fine\", too" okay
The simple join suggestions will yield: an, example, is "fine", too, okay. Not bad, but not very clear and somewhat misleading.
Here's what I threw together that works well enough for me. I'm sure it could be improved further.
String.Join(", ", (from a in args select '"' + a.Replace("\"", #"\""") + '"'));
It returns the string: "an", "example", "is \"fine\", too", "okay". I think this does a better job indicating the actual parameters.
String params = String.Join(",", args);
You should use:
string.Join(",", args);
Strictly speaking the Join function creates a StringBuilder with capacity strings.Length * 16 (this 16 is a fixed number). If you have different args maximum size and if performance is crucial to you, use a StringBuilder with a specific capacity.
I know the want for a "multi replace" in C# is no new concept, there are tons of solutions out there. However, I haven't came across any elegant solution that jives well with Linq to Sql. My proposal is to create an extension method (called, you guessed it, MultiReplace) that returns a lambda expression which chains multiple calls of Replace together. So in effect you would have the following:
x => x.SomeMember.MultiReplace("ABC", "-")
// Which would return a compiled expression equivalent to:
x => x.SomeMember.Replace("A", "-").Replace("B", "-").Replace("C", "-")
I'd like your thoughts/input/suggestions on this. Even if it turns out to be a bad idea, it still seems like a wicked opportunity to dive into expression trees. Your feedback is most appreciated.
-Eric
I'm not completely sure why you would want to do what you're describing. However if your motivation is to make more readable linq statements, by condensing some filtering logic, I suggest to look into the Specification Pattern.
If you only want to transform the result however, I would suggest to just do it in code, as there would only be a marginal benefit transforming on the server.
Some more examples on the Specification Pattern and Linq-to-SQL
I'm not sure what MultiReplace should be doing, or why you want to mix it with Linq to Sql. (Anything truly working with Linq to Sql would be translatable into SQL, which would be quite a lot of work, I think.)
The best solution I can think of is Regular Expressions. Why not use them? Linq to Sql may even translate them for you already, since MS SQL supports regular expressions.
x => Regex.Replace(x, "A|B|C", "-")
To me, this seems like a REALLY bad idea, it could be just because of your example, but the syntax you have listed to me is very confusing.
Reading this I would expect that
x => x.SomeMember.MultiReplace("ABC", "-")
If using the following text
ABC This Is A Test ABC Application
You would get something like
--- This Is A Test --- Application
But you are actually saying that it would be
--- This Is - Test --- -pplication
Which I see as problematic....
I'd also mention here that I don't really see a n urgent need for something like this. I guess if there was a need to do multiple replacemnts I'd do one of the following.
Chain them myself "myInput".Replace("m", "-").Replace("t", "-")
Create a function/method that accepts an ARRAY or List of strings for the matches, then a replacement character. Keeping it easy to understand.
Maybe there's no method that will do this, but you could simply nest the calls. Or make a static method that takes in a string and an array containing all its replacements. Another problem is that you need to actually specify a pair (the original substring, and its replacement).
I've never needed/wanted a feature like this.
The best way to do this would be:
static string MultiReplace(string this CSV, string Orig, string Replacement)
{
string final = "";
foreach (string s in CSV.Split(','))
{
final += s.Replace(Orig, Replacement);
}
return final;
}
Then you could call it with no ambiguity:
x => x.SomeMember.MultiReplace("A,B,C", "-")
If you expect that these strings will be longer than 3-4 values in the CSV, you might want to drop the concatenation in favor of a StringBuilder.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
How should I concatenate strings?
There are several ways to concat strings in everyday tasks when performance is not important.
result = a + ":" + b
result = string.Concat(a, ":", c)
result = string.Format("{0}:{1}", a, b);
StringBuilder approach
... ?
what do you prefer and why if efficiency doesn't matter but you want to keep the code most readable for your taste?
It depends on the use. When you just want to concat two strings, using a + b is just much more readable than string.Format("{0}{1}", a, b). However, it is getting more complex, I prefer using string.Format. Compare this:
string x = string.Format("-{0}- ({1})", a, b);
against:
string x = "-" + a + "- (" + b + ")";
I think that in most cases it is very easy to spot the most readable way to do things. In the cases where it is debatable which one is more readable, just pick one, because your boss isn't paying for these pointless discussions ;-)
string.Format for me, but in practice I use whichever is fit for purpose, taking into account performance and readability.
If it was two variables I'd use.
string.Concat(str1, str2);
If it contained a constant or something that requires formatting then.
string.Format("{0} + {1} = {2}", x, y, x + y);
Or for something like an SQL query
string SqlQuery = "SELECT col1, col2, col3, col4" +
"FROM table t " +
"WHERE col1 = 1";
And string builder when performance matters.
String.Format(...) is slowest.
For simple concatenations which don't take place in a loop, use String.Concat(...) or the + operator, which translate to the same under the hood, afaik. What is more readable is very subjective.
Using a StringBuilder for simple concatenations is over-the-top for simple concatenations as well and has most likely too much overhead. I'd only use it in a loop.
For something like this (which I'm guessing is being sent to the UI), I would definitely prefer String.Format. It allows the string to be internationalized easy; you can grep for calls to String.Format and replace them with your translating format.
My personal preference is:
I find the + approach the most readable and only use Format() or a StringBuilder if there is a good reason (i18n, performance etc) for it. I (almost) never use Concat.
I think I find the + approach easier to read than Format() simply because I don't have to skip ahead to the end to see what variables are put into in the {} place-holders. And if the place-holders aren't in numeric order, it gets even harder to read imo.
But I guess for larger projects it makes sense to simply enforce using Format by a style guide just in case the code might be (re-)used in a project requiring i18n later on.
string.Format
for few concats. for more I use
StringBuilder approach
even if performance is not important. there is a team agreement I have to follow
I prefer String.Format for small strings, and StringBuilder for larger ones. My main reason is readability. It's a lot more readable to me to use String.Format (or StringBuilder.AppendFormat()), but I have to admit that that is just personal preference.
For really big text generation, you might want to consider using the new (VS2010) T4 Preprocessed Templates - they are really nice.
Also, if you're ever in VB.NET, I like the XML literal technique Kathleen Dollard talked about in episode 152 of hanselminutes.
Prefer to use:
String.Concat for simple concatenations like String.Concat("foo", bar);
String.Format for complex formatting like String.Format("{1}", url, text);
StringBuilder for massive concatenations like:
var sb = new StringBuilder();
sb.AppendLine("function fooBar() {");
sp.AppendLine(String.Join(Environment.NewLine, blah));
sp.AppendLine("}");
page.RegisterClientScript(page.GetType(), sb.ToString());
Prefer to avoid "foo" + "bar" (as well as if (foo == "bar"). And especially String.Format("{0}{1}", foo, bar) and
throw new Exception("This code was" +
"written by developer with" +
"13\" monitor");