Каков самый быстрый способ подсчета строк в большой строке .NET?

Есть ли способ улучшить это:

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;
}

Меня особенно беспокоит элемент доступа к элементу в строке. Не уверен, что это просто арифметика указателя, такая как C/С++.

Ответы

Ответ 1

Я тестировал эти реализации

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;
}

Вот мои результаты синхронизации для 100000 итераций в строке ~ 25k. Нижний - быстрее.

              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

Удивительно, но для меня реализация Enumerator была самой быстрой для меня, в значительной степени - на 20% быстрее, чем следующая ближайшая реализация. Результаты повторялись, независимо от порядка, в котором выполнялись методы. Я также использовал фазу разминки, чтобы обеспечить переходные эффекты (jit и т.д.), Были учтены.

Это было для сборки релиза (/optimize +)

Ответ 2

Я уверен, что это будет не намного медленнее, чем преобразование строки в байты и ее проверка, если не быстрее. Класс String должен быть высоко оптимизирован.

Если это большая строка, возможно, параллельное выполнение несколькими потоками сделает вещи быстрее: -)

Ответ 3

Это, пожалуй, самый эффективный вариант - элемент доступа к объекту внутренне оптимизирован, и вы можете рассматривать его так, как будто он выполняет арифметику указателей.

Ответ 4

Ну, String реализует IEnumerable<char>, поэтому я определенно постараюсь:

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

Как ни странно, исходный метод в 30 раз быстрее:)

Я еще не отказался от IEnumerable, поэтому я также пробовал:

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

который выглядит так же быстро, как оригинальный метод.

Ответ 5

вы можете преобразовать строку в массив char с "ToCharArray();" но я не думаю, что это улучшит производительность. Вы можете попытаться использовать небезопасный код (указатель), а не для него, но хорошо, у которого есть свои недостатки.

Ответ 6

Сделайте это методом экземпляра, если вы будете использовать его в цикле.