Related
I have to write a program which use hashtable and the keys/values are input by the user. In the program, I have to output all the keys, however if any key starts with small 'a', I have to make it start with a big 'A'. I have a problem in the last step.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Hashtable hashtable = new Hashtable();
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Vnesete kluc");
string kluc = Console.ReadLine();
Console.WriteLine("Vnesete podatok");
string podatok = Console.ReadLine();
hashtable.Add(kluc, podatok);
}
foreach (string klucevi in hashtable.Keys)
{
if (klucevi[0] == 'a')
{
klucevi[0] = 'A';
}
Console.WriteLine(klucevi);
}
}
}
}
I'm getting an error on the line where I'm converting the first element of the string if it's 'a' to 'A'.
You can't dynamically change keys. Most simple approach is check the key before you add to the collection:
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Vnesete kluc");
string kluc = Console.ReadLine();
if (kluc.StartsWith("a"))
kluc = "A" + kluc.Substring(1);
Console.WriteLine("Vnesete podatok");
string podatok = Console.ReadLine();
hashtable.Add(kluc, podatok);
}
Your problem has nothing to do with hash tables. You have a compilation error, because in .NET strings are immutable.
Secondly, and this is unrelated, a foreach loop variable cannot be assigned to.
So, instead of
foreach (string klucevi in *whatever*)
{
if (klucevi[0] == 'a')
{
klucevi[0] = 'A';
}
Console.WriteLine(klucevi);
}
use
foreach (string klucevi in *whatever*)
{
var temp = klucevi;
if (temp[0] == 'a')
{
StringBuilder sb = new StringBuilder(temp);
sb[0] = 'A';
temp = sb.ToString();
}
Console.WriteLine(temp);
}
don't forget to include a using System.Text; declaration.
UPDATE:
The aswer above shows you a generic way to modify a string in .NET, not just to replace one character.
Furthermore, some people have raised concerns about the efficiency of the approach. They are mistaken. More information in this execelent article on Strings Undocumented.
UPDATE 2:
I like being challenged. While it is totally irrelevant for the question at hand, a discussion has emmerged about the efiiciency of using a StringBuilder, compared to using "A" + temp.Substring(1). Because I like facts, and I assume some readers would agree, I ran a little benchmark.
I ran the tests on a 64 bit Windows 7 box with .NET 4.5 as both a 32 and a 64 bit process. It turns out that the StringBuilder approach is always faster than the alternative, by about 20%. Memory usage is approximately the same. YMMV.
For those who care to repeat the test, here's the source code:
using System;
using System.Diagnostics;
using System.Text;
static class Program
{
static void Main(string[] args)
{
for (int length = 50; length <= 51200; length = length * 2)
{
string input = new string(' ', length);
// warm up
PerformTest(input, 1);
// actual test
PerformTest(input, 100000);
}
}
static void PerformTest(string input, int iterations)
{
GC.Collect();
GC.WaitForFullGCComplete();
int gcRuns = GC.CollectionCount(0);
Stopwatch sw = Stopwatch.StartNew();
for (int i = iterations; i > 0; i--)
{
StringBuilder sb = new StringBuilder(input);
sb[0] = 'A';
input = sb.ToString();
}
long ticksWithStringBuilder = sw.ElapsedTicks;
int gcRunsWithStringBuilder = GC.CollectionCount(0) - gcRuns;
GC.Collect();
GC.WaitForFullGCComplete();
gcRuns = GC.CollectionCount(0);
sw = Stopwatch.StartNew();
for (int i = iterations; i > 0; i--)
{
input = "A" + input.Substring(1);
}
long ticksWithConcatSubstring = sw.ElapsedTicks;
int gcRunsWithConcatSubstring = GC.CollectionCount(0) - gcRuns;
if (iterations > 1)
{
Console.WriteLine(
"String length: {0, 5} With StringBuilder {1, 9} ticks {2, 5} GC runs, alternative {3, 9} ticks {4, 5} GC Runs, speed ratio {5:0.00}",
input.Length,
ticksWithStringBuilder, gcRunsWithStringBuilder,
ticksWithConcatSubstring, gcRunsWithConcatSubstring,
((double)ticksWithStringBuilder) / ((double)ticksWithConcatSubstring));
}
}
}
Very brief question. I have a randomly sorted large string array (100K+ entries) where I want to find the first occurance of a desired string. I have two solutions.
From having read what I can my guess is that the 'for loop' is going to currently give slightly better performance (but this margin could always change), but I also find the linq version much more readable. On balance which method is generally considered current best coding practice and why?
string matchString = "dsf897sdf78";
int matchIndex = -1;
for(int i=0; i<array.length; i++)
{
if(array[i]==matchString)
{
matchIndex = i;
break;
}
}
or
int matchIndex = array.Select((r, i) => new { value = r, index = i })
.Where(t => t.value == matchString)
.Select(s => s.index).First();
The best practice depends on what you need:
Development speed and maintainability: LINQ
Performance (according to profiling tools): manual code
LINQ really does slow things down with all the indirection. Don't worry about it as 99% of your code does not impact end user performance.
I started with C++ and really learnt how to optimize a piece of code. LINQ is not suited to get the most out of your CPU. So if you measure a LINQ query to be a problem just ditch it. But only then.
For your code sample I'd estimate a 3x slowdown. The allocations (and subsequent GC!) and indirections through the lambdas really hurt.
Slightly better performance? A loop will give SIGNIFICANTLY better performance!
Consider the code below. On my system for a RELEASE (not debug) build, it gives:
Found via loop at index 999999 in 00:00:00.2782047
Found via linq at index 999999 in 00:00:02.5864703
Loop was 9.29700432810805 times faster than linq.
The code is deliberately set up so that the item to be found is right at the end. If it was right at the start, things would be quite different.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Demo
{
public static class Program
{
private static void Main(string[] args)
{
string[] a = new string[1000000];
for (int i = 0; i < a.Length; ++i)
{
a[i] = "Won't be found";
}
string matchString = "Will be found";
a[a.Length - 1] = "Will be found";
const int COUNT = 100;
var sw = Stopwatch.StartNew();
int matchIndex = -1;
for (int outer = 0; outer < COUNT; ++outer)
{
for (int i = 0; i < a.Length; i++)
{
if (a[i] == matchString)
{
matchIndex = i;
break;
}
}
}
sw.Stop();
Console.WriteLine("Found via loop at index " + matchIndex + " in " + sw.Elapsed);
double loopTime = sw.Elapsed.TotalSeconds;
sw.Restart();
for (int outer = 0; outer < COUNT; ++outer)
{
matchIndex = a.Select((r, i) => new { value = r, index = i })
.Where(t => t.value == matchString)
.Select(s => s.index).First();
}
sw.Stop();
Console.WriteLine("Found via linq at index " + matchIndex + " in " + sw.Elapsed);
double linqTime = sw.Elapsed.TotalSeconds;
Console.WriteLine("Loop was {0} times faster than linq.", linqTime/loopTime);
}
}
}
LINQ, according to declarative paradigm, expresses the logic of a computation without describing its control flow. The query is goal oriented, selfdescribing and thus easy to analyse and understand. Is also concise. Moreover, using LINQ, one depends highly upon abstraction of data structure. That involves high rate of maintanability and reusability.
Iteration aproach addresses imperative paradigm. It gives fine-grained control, thus ease obtain higher performance. The code is also simpler to debug. Sometimes well contructed iteration is more readable than query.
There is always dilemma between performance and maintainability. And usually (if there is no specific requirements about performance) maintainability should win. Only if you have performance problems, then you should profile application, find problem source, and improve its performance (by reducing maintainability at same time, yes that's the world we live in).
About your sample. Linq is not very good solution here, because it do not add match maintainability into your code. Actually for me projecting, filtering, and projecting again looks even worse, than simple loop. What you need here is simple Array.IndexOf, which is more maintainable, than loop, and have almost same performance:
Array.IndexOf(array, matchString)
Well, you gave the answer to your question yourself.
Go with a For loop if you want the best performance, or go with Linq if you want readability.
Also perhaps keep in mind the possibility of using Parallel.Foreach() which would benefit from in-line lambda expressions (so, more closer to Linq), and that is much more readable then doing paralelization "manually".
I don't think either is considered best practice some people prefer looking at LINQ and some don't.
If performance is a issue the I would profile both bits of code for your scenario and if the difference is negligible then go with the one you feel more conformable with, after all it will most likely be you who maintains the code.
Also have you thought about using PLINQ or making the loop run in parallel?
Just an interesting observation. LINQ Lambda queries for sure add a penalty over LINQ Where queries or a For Loop. In the following code, it fills a list with 1000001 multi-parameter objects and then searches for a specific item that in this test will always be the last one, using a LINQ Lamba, a LINQ Where Query and a For Loop. Each test iterates 100 times and then averages the times to get the results.
LINQ Lambda Query Average Time: 0.3382 seconds
LINQ Where Query Average Time: 0.238 seconds
For Loop Average Time: 0.2266 seconds
I've run this test over and over, and even increase the iteration and the spread is pretty much identical statistically speaking. Sure we are talking 1/10 of a second for essentially that a million item search. So in the real world, unless something is that intensive, not sure you would even notice. But if you do the LINQ Lambda vs LINQ Where query does have a difference in performance. The LINQ Where is near the same as the For Loop.
private void RunTest()
{
try
{
List<TestObject> mylist = new List<TestObject>();
for (int i = 0; i <= 1000000; i++)
{
TestObject testO = new TestObject(string.Format("Item{0}", i), 1, Guid.NewGuid().ToString());
mylist.Add(testO);
}
mylist.Add(new TestObject("test", "29863", Guid.NewGuid().ToString()));
string searchtext = "test";
int iterations = 100;
// Linq Lambda Test
List<int> list1 = new List<int>();
for (int i = 1; i <= iterations; i++)
{
DateTime starttime = DateTime.Now;
TestObject t = mylist.FirstOrDefault(q => q.Name == searchtext);
int diff = (DateTime.Now - starttime).Milliseconds;
list1.Add(diff);
}
// Linq Where Test
List<int> list2 = new List<int>();
for (int i = 1; i <= iterations; i++)
{
DateTime starttime = DateTime.Now;
TestObject t = (from testO in mylist
where testO.Name == searchtext
select testO).FirstOrDefault();
int diff = (DateTime.Now - starttime).Milliseconds;
list2.Add(diff);
}
// For Loop Test
List<int> list3 = new List<int>();
for (int i = 1; i <= iterations; i++)
{
DateTime starttime = DateTime.Now;
foreach (TestObject testO in mylist)
{
if (testO.Name == searchtext)
{
TestObject t = testO;
break;
}
}
int diff = (DateTime.Now - starttime).Milliseconds;
list3.Add(diff);
}
float diff1 = list1.Average();
Debug.WriteLine(string.Format("LINQ Lambda Query Average Time: {0} seconds", diff1 / (double)100));
float diff2 = list2.Average();
Debug.WriteLine(string.Format("LINQ Where Query Average Time: {0} seconds", diff2 / (double)100));
float diff3 = list3.Average();
Debug.WriteLine(string.Format("For Loop Average Time: {0} seconds", diff3 / (double)100));
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
private class TestObject
{
public TestObject(string _name, string _value, string _guid)
{
Name = _name;
Value = _value;
GUID = _guid;
}
public string Name;
public string Value;
public string GUID;
}
The Best Option Is To Use IndexOf method of Array Class. Since it is specialized for arrays it will b significantly faster than both Linq and For Loop.
Improving on Matt Watsons Answer.
using System;
using System.Diagnostics;
using System.Linq;
namespace PerformanceConsoleApp
{
public class LinqVsFor
{
private static void Main(string[] args)
{
string[] a = new string[1000000];
for (int i = 0; i < a.Length; ++i)
{
a[i] = "Won't be found";
}
string matchString = "Will be found";
a[a.Length - 1] = "Will be found";
const int COUNT = 100;
var sw = Stopwatch.StartNew();
Loop(a, matchString, COUNT, sw);
First(a, matchString, COUNT, sw);
Where(a, matchString, COUNT, sw);
IndexOf(a, sw, matchString, COUNT);
Console.ReadLine();
}
private static void Loop(string[] a, string matchString, int COUNT, Stopwatch sw)
{
int matchIndex = -1;
for (int outer = 0; outer < COUNT; ++outer)
{
for (int i = 0; i < a.Length; i++)
{
if (a[i] == matchString)
{
matchIndex = i;
break;
}
}
}
sw.Stop();
Console.WriteLine("Found via loop at index " + matchIndex + " in " + sw.Elapsed);
}
private static void IndexOf(string[] a, Stopwatch sw, string matchString, int COUNT)
{
int matchIndex = -1;
sw.Restart();
for (int outer = 0; outer < COUNT; ++outer)
{
matchIndex = Array.IndexOf(a, matchString);
}
sw.Stop();
Console.WriteLine("Found via IndexOf at index " + matchIndex + " in " + sw.Elapsed);
}
private static void First(string[] a, string matchString, int COUNT, Stopwatch sw)
{
sw.Restart();
string str = "";
for (int outer = 0; outer < COUNT; ++outer)
{
str = a.First(t => t == matchString);
}
sw.Stop();
Console.WriteLine("Found via linq First at index " + Array.IndexOf(a, str) + " in " + sw.Elapsed);
}
private static void Where(string[] a, string matchString, int COUNT, Stopwatch sw)
{
sw.Restart();
string str = "";
for (int outer = 0; outer < COUNT; ++outer)
{
str = a.Where(t => t == matchString).First();
}
sw.Stop();
Console.WriteLine("Found via linq Where at index " + Array.IndexOf(a, str) + " in " + sw.Elapsed);
}
}
}
Output:
Found via loop at index 999999 in 00:00:01.1528531
Found via linq First at index 999999 in 00:00:02.0876573
Found via linq Where at index 999999 in 00:00:01.3313111
Found via IndexOf at index 999999 in 00:00:00.7244812
A bit of a non-answer, and really just an extension to https://stackoverflow.com/a/14894589, but I have, on and off, been working on an API-compatible replacement for Linq-to-Objects for a while now. It still doesn't provide the performance of a hand-coded loop, but it is faster for many (most?) linq scenarios. It does create more garbage, and has some slightly heavier up front costs.
The code is available https://github.com/manofstick/Cistern.Linq
A nuget package is available https://www.nuget.org/packages/Cistern.Linq/ (I can't claim this to be battle hardened, use at your own risk)
Taking the code from Matthew Watson's answer (https://stackoverflow.com/a/14894589) with two slight tweaks, and we get the time down to "only" ~3.5 time worse than the hand-coded loop. On my machine it take about 1/3 of the time of original System.Linq version.
The two changes to replace:
using System.Linq;
...
matchIndex = a.Select((r, i) => new { value = r, index = i })
.Where(t => t.value == matchString)
.Select(s => s.index).First();
With the following:
// a complete replacement for System.Linq
using Cistern.Linq;
...
// use a value tuple rather than anonymous type
matchIndex = a.Select((r, i) => (value: r, index: i))
.Where(t => t.value == matchString)
.Select(s => s.index).First();
So the library itself is a work in progress. It fails a couple of edge cases from the corefx's System.Linq test suite. It also still needs a few functions to be converted over (they currently have the corefx System.Linq implementation, which is compatible from an API perspective, if not a performance perspective). But anymore who wants to help, comment, etc would be appreciated....
static void Main(string[] args)
{
string str = "ABC ABCDAB ABCDABCDABDE";//We should add some text here for
//the performance tests.
string pattern = "ABCDABD";
List<int> shifts = new List<int>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
NaiveStringMatcher(shifts, str, pattern);
stopWatch.Stop();
Trace.WriteLine(String.Format("Naive string matcher {0}", stopWatch.Elapsed));
foreach (int s in shifts)
{
Trace.WriteLine(s);
}
shifts.Clear();
stopWatch.Restart();
int[] pi = new int[pattern.Length];
Knuth_Morris_Pratt(shifts, str, pattern, pi);
stopWatch.Stop();
Trace.WriteLine(String.Format("Knuth_Morris_Pratt {0}", stopWatch.Elapsed));
foreach (int s in shifts)
{
Trace.WriteLine(s);
}
Console.ReadKey();
}
static IList<int> NaiveStringMatcher(List<int> shifts, string text, string pattern)
{
int lengthText = text.Length;
int lengthPattern = pattern.Length;
for (int s = 0; s < lengthText - lengthPattern + 1; s++ )
{
if (text[s] == pattern[0])
{
int i = 0;
while (i < lengthPattern)
{
if (text[s + i] == pattern[i])
i++;
else break;
}
if (i == lengthPattern)
{
shifts.Add(s);
}
}
}
return shifts;
}
static IList<int> Knuth_Morris_Pratt(List<int> shifts, string text, string pattern, int[] pi)
{
int patternLength = pattern.Length;
int textLength = text.Length;
//ComputePrefixFunction(pattern, pi);
int j;
for (int i = 1; i < pi.Length; i++)
{
j = 0;
while ((i < pi.Length) && (pattern[i] == pattern[j]))
{
j++;
pi[i++] = j;
}
}
int matchedSymNum = 0;
for (int i = 0; i < textLength; i++)
{
while (matchedSymNum > 0 && pattern[matchedSymNum] != text[i])
matchedSymNum = pi[matchedSymNum - 1];
if (pattern[matchedSymNum] == text[i])
matchedSymNum++;
if (matchedSymNum == patternLength)
{
shifts.Add(i - patternLength + 1);
matchedSymNum = pi[matchedSymNum - 1];
}
}
return shifts;
}
Why does my implemention of the KMP algorithm work slower than the Naive String Matching algorithm?
The KMP algorithm has two phases: first it builds a table, and then it does a search, directed by the contents of the table.
The naive algorithm has one phase: it does a search. It does that search much less efficiently in the worst case than the KMP search phase.
If the KMP is slower than the naive algorithm then that is probably because building the table is taking you longer than it takes to simply search the string naively in the first place. Naive string matching is usually very fast on short strings. There is a reason why we don't use fancy-pants algorithms like KMP inside the BCL implementations of string searching. By the time you set up the table, you could have done half a dozen searches of short strings with the naive algorithm.
KMP is only a win if you have enormous strings and you are doing lots of searches that allow you to re-use an already-built table. You need to amortize away the huge cost of building the table by doing lots of searches using that table.
And also, the naive algorithm only has bad performance in bizarre and unlikely scenarios. Most people are searching for words like "London" in strings like "Buckingham Palace, London, England", and not searching for strings like "BANANANANANANA" in strings like "BANAN BANBAN BANBANANA BANAN BANAN BANANAN BANANANANANANANANAN...". The naive search algorithm is optimal for the first problem and highly sub-optimal for the latter problem; but it makes sense to optimize for the former, not the latter.
Another way to put it: if the searched-for string is of length w and the searched-in string is of length n, then KMP is O(n) + O(w). The Naive algorithm is worst case O(nw), best case O(n + w). But that says nothing about the "constant factor"! The constant factor of the KMP algorithm is much larger than the constant factor of the naive algorithm. The value of n has to be awfully big, and the number of sub-optimal partial matches has to be awfully large, for the KMP algorithm to win over the blazingly fast naive algorithm.
That deals with the algorithmic complexity issues. Your methodology is also not very good, and that might explain your results. Remember, the first time you run code, the jitter has to jit the IL into assembly code. That can take longer than running the method in some cases. You really should be running the code a few hundred thousand times in a loop, discarding the first result, and taking an average of the timings of the rest.
If you really want to know what is going on you should be using a profiler to determine what the hot spot is. Again, make sure you are measuring the post-jit run, not the run where the code is jitted, if you want to have results that are not skewed by the jit time.
Your example is too small and it does not have enough repetitions of the pattern where KMP avoids backtracking.
KMP can be slower than the normal search in some cases.
A Simple KMPSubstringSearch Implementation.
https://github.com/bharathkumarms/AlgorithmsMadeEasy/blob/master/AlgorithmsMadeEasy/KMPSubstringSearch.cs
using System;
using System.Collections.Generic;
using System.Linq;
namespace AlgorithmsMadeEasy
{
class KMPSubstringSearch
{
public void KMPSubstringSearchMethod()
{
string text = System.Console.ReadLine();
char[] sText = text.ToCharArray();
string pattern = System.Console.ReadLine();
char[] sPattern = pattern.ToCharArray();
int forwardPointer = 1;
int backwardPointer = 0;
int[] tempStorage = new int[sPattern.Length];
tempStorage[0] = 0;
while (forwardPointer < sPattern.Length)
{
if (sPattern[forwardPointer].Equals(sPattern[backwardPointer]))
{
tempStorage[forwardPointer] = backwardPointer + 1;
forwardPointer++;
backwardPointer++;
}
else
{
if (backwardPointer == 0)
{
tempStorage[forwardPointer] = 0;
forwardPointer++;
}
else
{
int temp = tempStorage[backwardPointer];
backwardPointer = temp;
}
}
}
int pointer = 0;
int successPoints = sPattern.Length;
bool success = false;
for (int i = 0; i < sText.Length; i++)
{
if (sText[i].Equals(sPattern[pointer]))
{
pointer++;
}
else
{
if (pointer != 0)
{
int tempPointer = pointer - 1;
pointer = tempStorage[tempPointer];
i--;
}
}
if (successPoints == pointer)
{
success = true;
}
}
if (success)
{
System.Console.WriteLine("TRUE");
}
else
{
System.Console.WriteLine("FALSE");
}
System.Console.Read();
}
}
}
/*
* Sample Input
abxabcabcaby
abcaby
*/
I'm trying to insert a certain number of indentations before a string based on an items depth and I'm wondering if there is a way to return a string repeated X times. Example:
string indent = "---";
Console.WriteLine(indent.Repeat(0)); //would print nothing.
Console.WriteLine(indent.Repeat(1)); //would print "---".
Console.WriteLine(indent.Repeat(2)); //would print "------".
Console.WriteLine(indent.Repeat(3)); //would print "---------".
If you only intend to repeat the same character you can use the string constructor that accepts a char and the number of times to repeat it new String(char c, int count).
For example, to repeat a dash five times:
string result = new String('-', 5);
Output: -----
If you're using .NET 4.0, you could use string.Concat together with Enumerable.Repeat.
int N = 5; // or whatever
Console.WriteLine(string.Concat(Enumerable.Repeat(indent, N)));
Otherwise I'd go with something like Adam's answer.
The reason I generally wouldn't advise using Andrey's answer is simply that the ToArray() call introduces superfluous overhead that is avoided with the StringBuilder approach suggested by Adam. That said, at least it works without requiring .NET 4.0; and it's quick and easy (and isn't going to kill you if efficiency isn't too much of a concern).
most performant solution for string
string result = new StringBuilder().Insert(0, "---", 5).ToString();
public static class StringExtensions
{
public static string Repeat(this string input, int count)
{
if (string.IsNullOrEmpty(input) || count <= 1)
return input;
var builder = new StringBuilder(input.Length * count);
for(var i = 0; i < count; i++) builder.Append(input);
return builder.ToString();
}
}
For many scenarios, this is probably the neatest solution:
public static class StringExtensions
{
public static string Repeat(this string s, int n)
=> new StringBuilder(s.Length * n).Insert(0, s, n).ToString();
}
Usage is then:
text = "Hello World! ".Repeat(5);
This builds on other answers (particularly #c0rd's). As well as simplicity, it has the following features, which not all the other techniques discussed share:
Repetition of a string of any length, not just a character (as requested by the OP).
Efficient use of StringBuilder through storage preallocation.
Strings and chars [version 1]
string.Join("", Enumerable.Repeat("text" , 2 ));
//result: texttext
Strings and chars [version 2]:
String.Concat(Enumerable.Repeat("text", 2));
//result: texttext
Strings and chars [version 3]
new StringBuilder().Insert(0, "text", 2).ToString();
//result: texttext
Chars only:
new string('5', 3);
//result: 555
Extension way:
(works FASTER - better for WEB)
public static class RepeatExtensions
{
public static string Repeat(this string str, int times)
{
var a = new StringBuilder();
//Append is faster than Insert
( () => a.Append(str) ).RepeatAction(times) ;
return a.ToString();
}
public static void RepeatAction(this Action action, int count)
{
for (int i = 0; i < count; i++)
{
action();
}
}
}
usage:
var a = "Hello".Repeat(3);
//result: HelloHelloHello
Use String.PadLeft, if your desired string contains only a single char.
public static string Indent(int count, char pad)
{
return String.Empty.PadLeft(count, pad);
}
Credit due here
You can repeat your string (in case it's not a single char) and concat the result, like this:
String.Concat(Enumerable.Repeat("---", 5))
I would go for Dan Tao's answer, but if you're not using .NET 4.0 you can do something like that:
public static string Repeat(this string str, int count)
{
return Enumerable.Repeat(str, count)
.Aggregate(
new StringBuilder(str.Length * count),
(sb, s) => sb.Append(s))
.ToString();
}
string indent = "---";
string n = string.Concat(Enumerable.Repeat(indent, 1).ToArray());
string n = string.Concat(Enumerable.Repeat(indent, 2).ToArray());
string n = string.Concat(Enumerable.Repeat(indent, 3).ToArray());
Adding the Extension Method I am using all over my projects:
public static string Repeat(this string text, int count)
{
if (!String.IsNullOrEmpty(text))
{
return String.Concat(Enumerable.Repeat(text, count));
}
return "";
}
Hope someone can take use of it...
I like the answer given. Along the same lines though is what I've used in the past:
"".PadLeft(3*Indent,'-')
This will fulfill creating an indent but technically the question was to repeat a string. If the string indent is something like >-< then this as well as the accepted answer would not work. In this case, c0rd's solution using StringBuilder looks good, though the overhead of StringBuilder may in fact not make it the most performant. One option is to build an array of strings, fill it with indent strings, then concat that. To whit:
int Indent = 2;
string[] sarray = new string[6]; //assuming max of 6 levels of indent, 0 based
for (int iter = 0; iter < 6; iter++)
{
//using c0rd's stringbuilder concept, insert ABC as the indent characters to demonstrate any string can be used
sarray[iter] = new StringBuilder().Insert(0, "ABC", iter).ToString();
}
Console.WriteLine(sarray[Indent] +"blah"); //now pretend to output some indented line
We all love a clever solution but sometimes simple is best.
Surprised nobody went old-school.
I am not making any claims about this code, but just for fun:
public static string Repeat(this string #this, int count)
{
var dest = new char[#this.Length * count];
for (int i = 0; i < dest.Length; i += 1)
{
dest[i] = #this[i % #this.Length];
}
return new string(dest);
}
Print a line with repetition.
Console.Write(new string('=', 30) + "\n");
==============================
For general use, solutions involving the StringBuilder class are best for repeating multi-character strings. It's optimized to handle the combination of large numbers of strings in a way that simple concatenation can't and that would be difficult or impossible to do more efficiently by hand. The StringBuilder solutions shown here use O(N) iterations to complete, a flat rate proportional to the number of times it is repeated.
However, for very large number of repeats, or where high levels of efficiency must be squeezed out of it, a better approach is to do something similar to StringBuilder's basic functionality but to produce additional copies from the destination, rather than from the original string, as below.
public static string Repeat_CharArray_LogN(this string str, int times)
{
int limit = (int)Math.Log(times, 2);
char[] buffer = new char[str.Length * times];
int width = str.Length;
Array.Copy(str.ToCharArray(), buffer, width);
for (int index = 0; index < limit; index++)
{
Array.Copy(buffer, 0, buffer, width, width);
width *= 2;
}
Array.Copy(buffer, 0, buffer, width, str.Length * times - width);
return new string(buffer);
}
This doubles the length of the source/destination string with each iteration, which saves the overhead of resetting counters each time it would go through the original string, instead smoothly reading through and copying the now much longer string, something that modern processors can do much more efficiently.
It uses a base-2 logarithm to find how many times it needs to double the length of the string and then proceeds to do so that many times. Since the remainder to be copied is now less than the total length it is copying from, it can then simply copy a subset of what it has already generated.
I have used the Array.Copy() method over the use of StringBuilder, as a copying of the content of the StringBuilder into itself would have the overhead of producing a new string with that content with each iteration. Array.Copy() avoids this, while still operating with an extremely high rate of efficiency.
This solution takes O(1 + log N) iterations to complete, a rate that increases logarithmically with the number of repeats (doubling the number of repeats equals one additional iteration), a substantial savings over the other methods, which increase proportionally.
Another approach is to consider string as IEnumerable<char> and have a generic extension method which will multiply the items in a collection by the specified factor.
public static IEnumerable<T> Repeat<T>(this IEnumerable<T> source, int times)
{
source = source.ToArray();
return Enumerable.Range(0, times).SelectMany(_ => source);
}
So in your case:
string indent = "---";
var f = string.Concat(indent.Repeat(0)); //.NET 4 required
//or
var g = new string(indent.Repeat(5).ToArray());
Not sure how this would perform, but it's an easy piece of code. (I have probably made it appear more complicated than it is.)
int indentCount = 3;
string indent = "---";
string stringToBeIndented = "Blah";
// Need dummy char NOT in stringToBeIndented - vertical tab, anyone?
char dummy = '\v';
stringToBeIndented.PadLeft(stringToBeIndented.Length + indentCount, dummy).Replace(dummy.ToString(), indent);
Alternatively, if you know the maximum number of levels you can expect, you could just declare an array and index into it. You would probably want to make this array static or a constant.
string[] indents = new string[4] { "", indent, indent.Replace("-", "--"), indent.Replace("-", "---"), indent.Replace("-", "----") };
output = indents[indentCount] + stringToBeIndented;
I don't have enough rep to comment on Adam's answer, but the best way to do it imo is like this:
public static string RepeatString(string content, int numTimes) {
if(!string.IsNullOrEmpty(content) && numTimes > 0) {
StringBuilder builder = new StringBuilder(content.Length * numTimes);
for(int i = 0; i < numTimes; i++) builder.Append(content);
return builder.ToString();
}
return string.Empty;
}
You must check to see if numTimes is greater then zero, otherwise you will get an exception.
Using the new string.Create function, we can pre-allocate the right size and copy a single string in a loop using Span<char>.
I suspect this is likely to be the fastest method, as there is no extra allocation at all: the string is precisely allocated.
public static string Repeat(this string source, int times)
{
return string.Create(source.Length * times, source, RepeatFromString);
}
private static void RepeatFromString(Span<char> result, string source)
{
ReadOnlySpan<char> sourceSpan = source.AsSpan();
for (var i = 0; i < result.Length; i += sourceSpan.Length)
sourceSpan.CopyTo(result.Slice(i, sourceSpan.Length));
}
dotnetfiddle
I didn't see this solution. I find it simpler for where I currently am in software development:
public static void PrintFigure(int shapeSize)
{
string figure = "\\/";
for (int loopTwo = 1; loopTwo <= shapeSize - 1; loopTwo++)
{
Console.Write($"{figure}");
}
}
You can create an ExtensionMethod to do that!
public static class StringExtension
{
public static string Repeat(this string str, int count)
{
string ret = "";
for (var x = 0; x < count; x++)
{
ret += str;
}
return ret;
}
}
Or using #Dan Tao solution:
public static class StringExtension
{
public static string Repeat(this string str, int count)
{
if (count == 0)
return "";
return string.Concat(Enumerable.Repeat(indent, N))
}
}
I know we can append strings using StringBuilder. Is there a way we can prepend strings (i.e. add strings in front of a string) using StringBuilder so we can keep the performance benefits that StringBuilder offers?
Using the insert method with the position parameter set to 0 would be the same as prepending (i.e. inserting at the beginning).
C# example : varStringBuilder.Insert(0, "someThing");
Java example : varStringBuilder.insert(0, "someThing");
It works both for C# and Java
Prepending a String will usually require copying everything after the insertion point back some in the backing array, so it won't be as quick as appending to the end.
But you can do it like this in Java (in C# it's the same, but the method is called Insert):
aStringBuilder.insert(0, "newText");
If you require high performance with lots of prepends, you'll need to write your own version of StringBuilder (or use someone else's). With the standard StringBuilder (although technically it could be implemented differently) insert require copying data after the insertion point. Inserting n piece of text can take O(n^2) time.
A naive approach would be to add an offset into the backing char[] buffer as well as the length. When there is not enough room for a prepend, move the data up by more than is strictly necessary. This can bring performance back down to O(n log n) (I think). A more refined approach is to make the buffer cyclic. In that way the spare space at both ends of the array becomes contiguous.
Here's what you can do If you want to prepend using Java's StringBuilder class:
StringBuilder str = new StringBuilder();
str.Insert(0, "text");
You could try an extension method:
/// <summary>
/// kind of a dopey little one-off for StringBuffer, but
/// an example where you can get crazy with extension methods
/// </summary>
public static void Prepend(this StringBuilder sb, string s)
{
sb.Insert(0, s);
}
StringBuilder sb = new StringBuilder("World!");
sb.Prepend("Hello "); // Hello World!
You could build the string in reverse and then reverse the result.
You incur an O(n) cost instead of an O(n^2) worst case cost.
If I understand you correctly, the insert method looks like it'll do what you want. Just insert the string at offset 0.
I haven't used it but Ropes For Java Sounds intriguing. The project name is a play on words, use a Rope instead of a String for serious work. Gets around the performance penalty for prepending and other operations. Worth a look, if you're going to be doing a lot of this.
A rope is a high performance
replacement for Strings. The
datastructure, described in detail in
"Ropes: an Alternative to Strings",
provides asymptotically better
performance than both String and
StringBuffer for common string
modifications like prepend, append,
delete, and insert. Like Strings,
ropes are immutable and therefore
well-suited for use in multi-threaded
programming.
Try using Insert()
StringBuilder MyStringBuilder = new StringBuilder("World!");
MyStringBuilder.Insert(0,"Hello "); // Hello World!
You could create an extension for StringBuilder yourself with a simple class:
namespace Application.Code.Helpers
{
public static class StringBuilderExtensions
{
#region Methods
public static void Prepend(this StringBuilder sb, string value)
{
sb.Insert(0, value);
}
public static void PrependLine(this StringBuilder sb, string value)
{
sb.Insert(0, value + Environment.NewLine);
}
#endregion
}
}
Then, just add:
using Application.Code.Helpers;
To the top of any class that you want to use the StringBuilder in and any time you use intelli-sense with a StringBuilder variable, the Prepend and PrependLine methods will show up. Just remember that when you use Prepend, you will need to Prepend in reverse order than if you were Appending.
Judging from the other comments, there's no standard quick way of doing this. Using StringBuilder's .Insert(0, "text") is approximately only 1-3x as fast as using painfully slow String concatenation (based on >10000 concats), so below is a class to prepend potentially thousands of times quicker!
I've included some other basic functionality such as append(), subString() and length() etc. Both appends and prepends vary from about twice as fast to 3x slower than StringBuilder appends. Like StringBuilder, the buffer in this class will automatically increase when the text overflows the old buffer size.
The code has been tested quite a lot, but I can't guarantee it's free of bugs.
class Prepender
{
private char[] c;
private int growMultiplier;
public int bufferSize; // Make public for bug testing
public int left; // Make public for bug testing
public int right; // Make public for bug testing
public Prepender(int initialBuffer = 1000, int growMultiplier = 10)
{
c = new char[initialBuffer];
//for (int n = 0; n < initialBuffer; n++) cc[n] = '.'; // For debugging purposes (used fixed width font for testing)
left = initialBuffer / 2;
right = initialBuffer / 2;
bufferSize = initialBuffer;
this.growMultiplier = growMultiplier;
}
public void clear()
{
left = bufferSize / 2;
right = bufferSize / 2;
}
public int length()
{
return right - left;
}
private void increaseBuffer()
{
int nudge = -bufferSize / 2;
bufferSize *= growMultiplier;
nudge += bufferSize / 2;
char[] tmp = new char[bufferSize];
for (int n = left; n < right; n++) tmp[n + nudge] = c[n];
left += nudge;
right += nudge;
c = new char[bufferSize];
//for (int n = 0; n < buffer; n++) cc[n]='.'; // For debugging purposes (used fixed width font for testing)
for (int n = left; n < right; n++) c[n] = tmp[n];
}
public void append(string s)
{
// If necessary, increase buffer size by growMultiplier
while (right + s.Length > bufferSize) increaseBuffer();
// Append user input to buffer
int len = s.Length;
for (int n = 0; n < len; n++)
{
c[right] = s[n];
right++;
}
}
public void prepend(string s)
{
// If necessary, increase buffer size by growMultiplier
while (left - s.Length < 0) increaseBuffer();
// Prepend user input to buffer
int len = s.Length - 1;
for (int n = len; n > -1; n--)
{
left--;
c[left] = s[n];
}
}
public void truncate(int start, int finish)
{
if (start < 0) throw new Exception("Truncation error: Start < 0");
if (left + finish > right) throw new Exception("Truncation error: Finish > string length");
if (finish < start) throw new Exception("Truncation error: Finish < start");
//MessageBox.Show(left + " " + right);
right = left + finish;
left = left + start;
}
public string subString(int start, int finish)
{
if (start < 0) throw new Exception("Substring error: Start < 0");
if (left + finish > right) throw new Exception("Substring error: Finish > string length");
if (finish < start) throw new Exception("Substring error: Finish < start");
return toString(start,finish);
}
public override string ToString()
{
return new string(c, left, right - left);
//return new string(cc, 0, buffer); // For debugging purposes (used fixed width font for testing)
}
private string toString(int start, int finish)
{
return new string(c, left+start, finish-start );
//return new string(cc, 0, buffer); // For debugging purposes (used fixed width font for testing)
}
}
This should work:
aStringBuilder = "newText" + aStringBuilder;