I am working on an optimization pass for our asp.net web application and I want to shrink down and speed up as much of the backend as I can.
Is there any way to shrink down a for loop so that it becomes a lambda expression maybe?
A pure example of something that I might want to shrink down:
string outS = "";
for (int i = 0; i < length; i++)
{
outS += random.Next(0, 9).ToString();
}
return int.Parse(outS).ToString();
Instead of creating a new variable, performing some sort of function to generate it, and then returning it, is there a way where I can do all that in a single line? Like returning a lambda expression function?
Or is the current functionality the fastest way to do it anyway?
Like this silly example:
return => for(int i = 0; i < length; i++)
{
random.Next(0, 9).ToString();
}
If the logic method returns a random number that has a specified number of digits in the length variable, you could do something like this:
private int TestMethod(int length) =>
new Random().Next((int)Math.Pow(10, length - 1), (int)Math.Pow(10, length));
This form has some adventages:
No string concatenation. String concatenation is not recommended if many concatenations are performed.
The number of times a random number is requested is reduced (in the above code, the Random.Next method is only invoked once).
Nevertheless, it's a good practice that you perform a profiler comparing alternatives. You can do it with the Diagnostic Tools View in Visual Studio, and with the StopWatch class
If you're just wondering about condensing lines of code, you can use Linq's ForEach method and pass in a lambda expression.
This:
string outS = "";
for (int i = 0; i < length; i++)
{
outS += random.Next(0, 9).ToString();
}
return int.Parse(outS).ToString();
Becomes this:
string outS = "";
new List<int>(10).ForEach(_ => outS += random.Next(0, 9).ToString());
return int.Parse(outS).ToString();
Related
I'm having trouble thinking of a logical way to achieve this. I have a method which sends a web request with a for loop that is counting up from 1 to x, the request counts up until it finds a specific response and then sends the URL + number to another method.
After this, saying we got the number 5, I need to create a string which displays as "1,2,3,4,5" but cannot seem to find a way to create the entire string, everything I try is simply replacing the string and only keeping the last number.
string unionMod = string.Empty;
for (int i = 1; i <= count; i++)
{
unionMod =+ count + ",";
}
I assumed I'd be able to simply add each value onto the end of the string but the output is just "5," with it being the last number. I have looked around but I can't seem to even think of what I would search in order to get the answer, I have a hard-coded solution but ideally, I'd like to not have a 30+ string with each possible value and just have it created when needed.
Any pointers?
P.S: Any coding examples are appreciated but I've probably just forgotten something obvious so any directions you can give are much appreciated, I should sleep but I'm on one of those all-night coding grinds.
Thank you!
First of all your problem is the +=. You should avoid concatenating strings because it allocates a new string. Instead you should use a StringBuilder.
Your Example: https://dotnetfiddle.net/Widget/qQIqWx
My Example: https://dotnetfiddle.net/Widget/sx7cxq
public static void Main()
{
var counter = 5;
var sb = new StringBuilder();
for(var i = 1; i <= counter; ++i) {
sb.Append(i);
if (i != counter) {
sb.Append(",");
}
}
Console.WriteLine(sb);
}
As it's been pointed out, you should use += instead of =+. The latter means "take count and append a comma to it", which is the incorrect result you experienced.
You could also simplify your code like this:
int count = 10;
string unionMod = String.Join(",", Enumerable.Range(1, count));
Enumerable.Range generates a sequence of integers between its two parameters and String.Join joins them up with the given separator character.
I'm interested in doing something like this (C#):
int sum = 0;
for (int i = 0; i < 5; i++)
sum += i;
But I would like to do it on one line. Something like:
int sum = (embedded loop)
Is there any way to do this on one line? I'm looking to apply this to a more complex string manipulation algorithm so I can't simply replace the loop with an arithmatic formula.
So you want to loop and do something in one line?
First off, writing it in one line isn't going to make it run faster. You are still going to loop, you are still going to be O(n). For the particular problem you have in your question you can do something like:
var sum = Enumerable.Range(0,5).Sum();
This will basically make a collection of the numbers 0,1,2...4 and sum them.
More generally, since you want to do something, you might use the Aggregate function. For example:
var str = Enumerable.Range(0,5).Aggregate("",(p,c) => p + c); // Note: not efficient at all
Will take the values 0,1,...4 and do string concatenation with them (using a string builder would be better) to give you the string 01234.
Edit:
I'm trying to loop through a list of words and make each one title case, then return the string[].join(" ") of it
In that case, something like:
var result = string.Join(" ", myListOfWords.Select(w => char.ToUpper(w[0]) + w.Substring(1)));
Should work fine.
If you don't mind that 'sum' only is in scope of the for loop you could do this:
for (int i = 0, sum = 0; i < 5; sum += i, ++i) { // do something }
for(int i=0,sum = 0; i<5; sum+=i,++i){}
Which of these methods are the most efficient one or is there a better way to do it?
this.returnList[i].Title[0].ToString()
or
this.returnList[i].Title.Substring(0, 1)
They're both very fast:
Char Index
var sample = "sample";
var clock = new Stopwatch();
for (var i = 0; i < 10; i++)
{
clock.Start();
for (var j = 0; j < 10000000; j++)
{
var first = sample[0].ToString();
}
clock.Stop();
Console.Write(clock.Elapsed);
clock.Reset();
}
// Results
00:00:00.2012243
00:00:00.2207168
00:00:00.2184807
00:00:00.2258847
00:00:00.2296456
00:00:00.2261465
00:00:00.2120131
00:00:00.2221702
00:00:00.2346083
00:00:00.2330840
Substring
var sample = "sample";
var clock = new Stopwatch();
for (var i = 0; i < 10; i++)
{
clock.Start();
for (var j = 0; j < 10000000; j++)
{
var first = sample.Substring(0, 1);
}
clock.Stop();
Console.Write(clock.Elapsed);
clock.Reset();
}
// Results
00:00:00.3268155
00:00:00.3337077
00:00:00.3439908
00:00:00.3273090
00:00:00.3380794
00:00:00.3400650
00:00:00.3280275
00:00:00.3333719
00:00:00.3295982
00:00:00.3368425
I also agree with BrokenGlass that using the char index is a cleaner way of writing it. Plus if you're doing it 10 trillion times it'll be much faster!
There is a big loophole in your code that may cause problems, depending on what you mean by "first character" and what returnList contains.
C# strings contain UTF-16, which is a variable-length encoding, and if returnList is an array of strings, then returnList[i] might only be one char of a Unicode point. If you want to return the first Unicode grapheme of a string:
string s = returnList[i].Title;
if (string.IsNullOrEmpty(s))
return s;
int charsInGlyph = char.IsSurrogatePair(s, 0) ? 2 : 1;
return s.Substring(0, charsInGlyph);
You can run into the same problems with BOMs, tagged, and combining characters; these are all valid characters but are not meaningful if displayed to a user.
If you want Unicode points or graphemes, not chars, you must use strings; Unicode graphemes can be more than one char.
I don't think it would matter much efficiency wise, but in my opinion the clearer, more idiomatic and hence more maintainable way of returning the first character is using the index operator:
char c = returnList[i].Title[0];
This assumes of course there is at least one character, if that's not a given you have to check for that.
Those should be close to identical in performance.
The expensive part of the operation is to create the string, and there is no more efficient way to do that.
Unless of couse you want to pre-create strings for all possible characters and store in a dictionary, but that would use up a lot of memory for such a trivial task.
returnList[I].Title[0] is much faster as it does not need to create a new string, only accessing a char from the original one.
Of course, it will throw an exception if the string is empty, so you should check that first.
As a rule of thumb, never use strings with a fixed length of 1. that's what char is for.
The performance difference is not likely to matter though, but the better readability certainly will.
So, I've written a small and, from what I initially thought, easy method in C#.
This static method is meant to be used as a simple password suggestion generator, and the code looks like this:
public static string CreateRandomPassword(int outputLength, string source = "")
{
var output = string.Empty;
for (var i = 0; i < outputLength; i++)
{
var randomObj = new Random();
output += source.Substring(randomObj.Next(source.Length), 1);
}
return output;
}
I call this function like this:
var randomPassword = StringHelper.CreateRandomPassword(5, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
Now, this method almost always return random strings like "AAAAAA", "BBBBBB", "888888" etc.. , where I thought it should return strings like "A8JK2A", "82mOK7" etc.
However, and here is the wierd part; If I place a breakpoint, and step through this iteration line by line, I get the correct type of password in return. In 100% of the other cases, when Im not debugging, it gives me crap like "AAAAAA", "666666", etc..
How is this possible? Any suggestion is greatly appreciated! :-)
BTW, my system: Visual Studio 2010, C# 4.0, ASP.NET MVC 3 RTM project w/ ASP.NET Development Server. Haven't tested this code in any other environments.
Move the declaration for the randomObj outside the loop. When you're debugging it, it creates it with a new seed each time, because there's enough time difference for the seed to be different. But when you're not debugging, the seed time is basically the same for each iteration of the loop, so it's giving you the same start value each time.
And a minor nit -- it's a good habit to use a StringBuilder rather than a string for this sort of thing, so you don't have to re-initialize the memory space every time you append a character to the string.
In other words, like this:
public static string CreateRandomPassword(int outputLength, string source = "")
{
var output = new StringBuilder();
var randomObj = new Random();
for (var i = 0; i < outputLength; i++)
{
output.Append(source.Substring(randomObj.Next(source.Length), 1));
}
return output.ToString();
}
The behavior you're seeing is because Random is time-based, and when you're not debugging it flies through all 5 iterations at the same moment (more or less). So you're asking for the first random number off the same seed. When you're debugging, it takes long enough to get a new seed each time.
Move the declaration of Random outside the loop:
var randomObj = new Random();
for (var i = 0; i < outputLength; i++)
{
output += source.Substring(randomObj.Next(source.Length), 1);
}
Now you're moving forward 5 steps away from a Random seed instead of moving 1 step away from the same Random seed 5 times.
You are instantiating a new instance of Random() on each iteration through the loop with a new time-dependent seed. Given the granularity of the system clock and the speed of modern CPUs, this pretty much guarantees that you restart the pseudo-random sequence over and over with the same seed.
Try something like the following, though if you're single-threaded, you can safely omit the lock():
private static Random randomBits = new Random() ;
public static string CreateRandomPassword(int outputLength, string source = "")
{
StringBuilder sb = new StringBuilder(outputLength) ;
lock ( randomBits )
{
while ( sb.Length < outputLength )
{
sb.Append( randomBits.Next( source.Length) , 1 ) ;
}
}
return sb.ToString() ;
}
You only instantiate the RNG once. Every draws bits from the same RNG, so it should behave much more like a source of entropy. If you need repeatability for testing, use the Random constructor overload that lets you supply the seed. Same seed == same pseudo-random sequence.
I'm trying to figure out the time complexity of a function that I wrote (it generates a power set for a given string):
public static HashSet<string> GeneratePowerSet(string input)
{
HashSet<string> powerSet = new HashSet<string>();
if (string.IsNullOrEmpty(input))
return powerSet;
int powSetSize = (int)Math.Pow(2.0, (double)input.Length);
// Start at 1 to skip the empty string case
for (int i = 1; i < powSetSize; i++)
{
string str = Convert.ToString(i, 2);
string pset = str;
for (int k = str.Length; k < input.Length; k++)
{
pset = "0" + pset;
}
string set = string.Empty;
for (int j = 0; j < pset.Length; j++)
{
if (pset[j] == '1')
{
set = string.Concat(set, input[j].ToString());
}
}
powerSet.Add(set);
}
return powerSet;
}
So my attempt is this:
let the size of the input string be n
in the outer for loop, must iterate 2^n times (because the set size is 2^n).
in the inner for loop, we must iterate 2*n times (at worst).
1. So Big-O would be O((2^n)*n) (since we drop the constant 2)... is that correct?
And n*(2^n) is worse than n^2.
if n = 4 then
(4*(2^4)) = 64
(4^2) = 16
if n = 100 then
(10*(2^10)) = 10240
(10^2) = 100
2. Is there a faster way to generate a power set, or is this about optimal?
A comment:
the above function is part of an interview question where the program is supposed to take in a string, then print out the words in the dictionary whose letters are an anagram subset of the input string (e.g. Input: tabrcoz Output: boat, car, cat, etc.). The interviewer claims that a n*m implementation is trivial (where n is the length of the string and m is the number of words in the dictionary), but I don't think you can find valid sub-strings of a given string. It seems that the interviewer is incorrect.
I was given the same interview question when I interviewed at Microsoft back in 1995. Basically the problem is to implement a simple Scrabble playing algorithm.
You are barking up completely the wrong tree with this idea of generating the power set. Nice thought, clearly way too expensive. Abandon it and find the right answer.
Here's a hint: run an analysis pass over the dictionary that builds a new data structure more amenable to efficiently solving the problem you actually have to solve. With an optimized dictionary you should be able to achieve O(nm). With a more cleverly built data structure you can probably do even better than that.
2. Is there a faster way to generate a power set, or is this about optimal?
Your algorithm is reasonable, but your string handling could use improvement.
string str = Convert.ToString(i, 2);
string pset = str;
for (int k = str.Length; k < input.Length; k++)
{
pset = "0" + pset;
}
All you're doing here is setting up a bitfield, but using a string. Just skip this, and use variable i directly.
for (int j = 0; j < input.Length; j++)
{
if (i & (1 << j))
{
When you build the string, use a StringBuilder, not creating multiple strings.
// At the beginning of the method
StringBuilder set = new StringBuilder(input.Length);
...
// Inside the loop
set.Clear();
...
set.Append(input[j]);
...
powerSet.Add(set.ToString());
Will any of this change the complexity of your algorithm? No. But it will significantly reduce the number of extra String objects you create, which will provide you a good speedup.