tags:

views:

288

answers:

6

Is there a way to improve this:

private static int CountNewlines(string s)
{
    int len = s.Length;
    int c = 0;
    for (int i=0; i < len;  i++)
    {
        if (s[i] == '\n') c++;
    }
    return c;
}

I'm particularly concerned about the Item accessor on the string. Not sure if it is just pointer arithmetic like C/C++.

+4  A: 

This is probably the most efficient option - the item accessor is internally optimized and you can treat it as if it performs pointer arithmentic.

LBushkin
A: 

you could convert the string to a char array with "ToCharArray();" but i don't think it will improve the performance.. you could try to use unsafe code (pointer) instead of for but well that has its drawbacks to.

Petoj
Right, I could do that. I haven't tried that. It's a large string, and it will be called repeatedly, so I'm inclined to avoid creating new arrays just to count it.
Cheeso
Will this be called on the same string more then once? You could have a dictonary with à weakreference as key and a int as result. This way you can cache the result..
Petoj
+6  A: 

I'm pretty sure this won't be much slower than converting the string to bytes and checking those, if not faster. The String class should be highly optimized.

If this is a big string, maybe a parallel execution by several threads will make things faster :-)

M.A. Hanin
Parallel execution would only speed things up on a multicore/multiprocessor machine - but it can be an option for *really* big strings.
LBushkin
Sure, and there is no point in creating more threads than the total amount of cores. If this string contains many line-breaks, it may just be a very big text file or something, so the OP may actually use this option...
M.A. Hanin
A: 

Make it an instance method, if you'll use it in a loop.

Snoop Dogg
How does this matter?
0xA3
like when using systemIO , calling file.Copy and new FileInfo .. .Copy(). Its from O'Reilly C# Cookbook
Snoop Dogg
+1  A: 

Well, String implements IEnumerable<char>, so I'd definitely try:

s.Count( c => c == '\n' )

As nice as this looks, the original method is 30x faster :)

I haven't given up on the IEnumerable yet, so I've also tried:

int n = 0;
foreach( var c in s )
{
    if ( c == '\n' ) n++;
}
return n;

which seems as fast as the original method.

Danko Durbić
+3  A: 

I tested these implementations

private static int Count1(string s)
{
    int len = s.Length;
    int c = 0;
    for (int i=0; i < len;  i++)
    {
        if (s[i] == '\n') c++;
    }
    return c+1;
}

private static int Count2(string s)
{
    int count = -1;
    int index = -1;

    do
    {
        count++;
        index = s.IndexOf('\n', index + 1);
    }
    while (index != -1);

    return count+1;
}

private static int Count3(string s)
{
    return s.Count( c => c == '\n' ) + 1;
}


private static int Count4(string s)
{
    int n = 0;
    foreach( var c in s )
    {
        if ( c == '\n' ) n++;
    }
    return n+1;
}

private static int Count5(string s)
{
    var a = s.ToCharArray();
    int c = 0;
    for (int i=0; i < a.Length; i++)
    {
        if (a[i]=='\n') c++;
    }
    return c+1;
}

Here are my timing results for 100000 iterations on a string of ~25k. Lower is faster.

              Time  Factor
Count1   4.8581503     1.4
Count2   4.1406059     1.2
Count3  45.3614124    13.4
Count4   3.3896130     1.0
Count5   5.9304543     1.7

Surprisingly, to me, the Enumerator implementation was fastest for me, by a significant degree - 20% faster than the next closest implementation. The results were repeatable, regardless of the order in which the methods were run. I also used a warmup phase to insure transient effects (jit, etc) were factored out.

This was for a release build (/optimize+)

Cheeso