Подтвердить что ты не робот

Что является самым быстрым (встроенным) сравнением для типов строк в С#

Каков самый быстрый встроенный метод сравнения для строковых типов в С#? Я не возражаю против типографского/семантического значения: цель состоит в том, чтобы использовать компаратор в отсортированных списках для быстрого поиска в больших коллекциях. Я думаю, что существует только два метода: Compare и CompareOrdinal. Какой самый быстрый?

Кроме того, существует ли более быстрый метод для сравнения строк?

4b9b3361

Ответ 1

Я предполагаю, что вы хотите меньше, чем/равно/больше, чем сравнение, а не просто равенство; равенство - это немного другая тема, хотя принципы в основном одинаковы. Если вы на самом деле ищете только что-то вроде SortedList, я бы подумал об использовании Dictionary<string, XXX> - вам действительно нужна вся эта сортировка?

String.CompareOrdinal, или используя перегрузку String.Compare, которая позволяет обеспечить сравнение, и указание порядкового (чувствительного к регистру) сравнения, например. String.Compare(x, y, StringComparison.Ordinal) будет самым быстрым.

В принципе, для сравнения по порядку просто нужно пройти две строки, характер по характеру, пока не найдет разницу. Если он не находит различий, а длины одинаковы, результат равен 0. Если он не находит различий, а длины не совпадают, более длинная строка считается "больше". Если он найдет разницу, он может сразу же выработать, который считается "большим", на основе которого символ "больше" в порядковых терминах.

Иными словами, он делает очевидное сравнение между двумя значениями char[].

Культурно-чувствительные сравнения должны выполнять все виды извилистых умений, в зависимости от точной культуры, которую вы используете. Например, см. этот вопрос. Довольно ясно, что выполнение более сложных правил может сделать это медленнее.

Ответ 2

Я только что заметил 50% -ное увеличение производительности в моем собственном коде, сначала сравнив длины строк, а затем равный, используя методы string.compare. Поэтому в цикле я:

VB:

If strA.length = strB.length then
   if string.compare(strA,strB,true) = 0 then
      TheyAreEqual
   End if
End if

С#

if(strA.Length == strB.Length)
{
   if(string.Compare(strA,strB,true) == 0)
   {
       //they are equal
   }
}

Это может зависеть от ваших собственных строк, но, похоже, это сработало для меня.

Ответ 3

Fastest - это интернированные строки с эталонным тестом на равенство, но вы получаете только тестирование на равенство, и это связано с большим объемом памяти - настолько дорогостоящим, что почти никогда не рекомендуется.

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

Если вы укажете либо StringComparison.Ordinal, либо StringComparison.OrdinalIgnoreCase, сравнение строк будет нелингвистическим. То есть, функции, характерные для естественного языка, игнорируются при принятии решений о сопоставлении. Это означает, что решения основаны на простых сравнениях байтов и игнорируют таблицы обтекания или эквивалентности, которые параметризуются культурой. В результате, явно устанавливая параметр как StringComparison.Ordinal или StringComparison.OrdinalIgnoreCase, ваш код часто получает скорость, повышает правильность и становится более надежным.

Источник

Ответ 4

Я разработал unit test для проверки скорости сравнения строк, используя некоторые из методов, упомянутых в этом сообщении. Этот тест выполнялся с использованием .NET 4

Короче говоря, нет большой разницы, и мне пришлось перейти на 100 000 000 итераций, чтобы увидеть существенную разницу. Поскольку кажется, что персонажи сравниваются по очереди, пока не будет найдена разница, неизбежно, насколько подобны строки, которые играют роль.

Эти результаты на самом деле показывают, что использование str1.Equals(str2) является самым быстрым способом сравнения строк.

Это результаты теста с включенным тестовым классом:

######## SET 1 compared strings are the same: 0
#### Basic == compare: 413
#### Equals compare: 355
#### Equals(compare2, StringComparison.Ordinal) compare: 387
#### String.Compare(compare1, compare2, StringComparison.Ordinal) compare: 426
#### String.CompareOrdinal(compare1, compare2) compare: 412

######## SET 2 compared strings are NOT the same: 0
#### Basic == compare: 710
#### Equals compare: 733
#### Equals(compare2, StringComparison.Ordinal) compare: 840
#### String.Compare(compare1, compare2, StringComparison.Ordinal) compare: 987
#### String.CompareOrdinal(compare1, compare2) compare: 776

using System;
using System.Diagnostics;
using NUnit.Framework;

namespace Fwr.UnitTests
{
    [TestFixture]
    public class StringTests
    {
        [Test]
        public void Test_fast_string_compare()
        {
            int iterations = 100000000;
            bool result = false;
            var stopWatch = new Stopwatch();

            Debug.WriteLine("######## SET 1 compared strings are the same: " + stopWatch.ElapsedMilliseconds);

            string compare1 = "xxxxxxxxxxxxxxxxxx";
            string compare2 = "xxxxxxxxxxxxxxxxxx";

            // Test 1

            stopWatch.Start();

            for (int i = 0; i < iterations; i++)
            {
                result = compare1 == compare2;
            }

            stopWatch.Stop();

            Debug.WriteLine("#### Basic == compare: " + stopWatch.ElapsedMilliseconds);

            stopWatch.Reset();

            // Test 2

            stopWatch.Start();

            for (int i = 0; i < iterations; i++)
            {
                result = compare1.Equals(compare2);
            }

            stopWatch.Stop();

            Debug.WriteLine("#### Equals compare: " + stopWatch.ElapsedMilliseconds);

            stopWatch.Reset();

            // Test 3

            stopWatch.Start();

            for (int i = 0; i < iterations; i++)
            {
                result = compare1.Equals(compare2, StringComparison.Ordinal);
            }

            stopWatch.Stop();

            Debug.WriteLine("#### Equals(compare2, StringComparison.Ordinal) compare: " + stopWatch.ElapsedMilliseconds);

            stopWatch.Reset();

            // Test 4

            stopWatch.Start();

            for (int i = 0; i < iterations; i++)
            {
                result = String.Compare(compare1, compare2, StringComparison.Ordinal) != 0;
            }

            stopWatch.Stop();

            Debug.WriteLine("#### String.Compare(compare1, compare2, StringComparison.Ordinal) compare: " + stopWatch.ElapsedMilliseconds);

            stopWatch.Reset();

            // Test 5

            stopWatch.Start();

            for (int i = 0; i < iterations; i++)
            {
                result = String.CompareOrdinal(compare1, compare2) != 0;
            }

            stopWatch.Stop();

            Debug.WriteLine("#### String.CompareOrdinal(compare1, compare2) compare: " + stopWatch.ElapsedMilliseconds);

            stopWatch.Reset();

            Debug.WriteLine("######## SET 2 compared strings are NOT the same: " + stopWatch.ElapsedMilliseconds);

            compare1 = "ueoqwwnsdlkskjsowy";
            compare2 = "sakjdjsjahsdhsjdak";

            // Test 1

            stopWatch.Start();

            for (int i = 0; i < iterations; i++)
            {
                result = compare1 == compare2;
            }

            stopWatch.Stop();

            Debug.WriteLine("#### Basic == compare: " + stopWatch.ElapsedMilliseconds);

            stopWatch.Reset();

            // Test 2

            stopWatch.Start();

            for (int i = 0; i < iterations; i++)
            {
                result = compare1.Equals(compare2);
            }

            stopWatch.Stop();

            Debug.WriteLine("#### Equals compare: " + stopWatch.ElapsedMilliseconds);

            stopWatch.Reset();

            // Test 3

            stopWatch.Start();

            for (int i = 0; i < iterations; i++)
            {
                result = compare1.Equals(compare2, StringComparison.Ordinal);
            }

            stopWatch.Stop();

            Debug.WriteLine("#### Equals(compare2, StringComparison.Ordinal) compare: " + stopWatch.ElapsedMilliseconds);

            stopWatch.Reset();

            // Test 4

            stopWatch.Start();

            for (int i = 0; i < iterations; i++)
            {
                result = String.Compare(compare1, compare2, StringComparison.Ordinal) != 0;
            }

            stopWatch.Stop();

            Debug.WriteLine("#### String.Compare(compare1, compare2, StringComparison.Ordinal) compare: " + stopWatch.ElapsedMilliseconds);

            stopWatch.Reset();

            // Test 5

            stopWatch.Start();

            for (int i = 0; i < iterations; i++)
            {
                result = String.CompareOrdinal(compare1, compare2) != 0;
            }

            stopWatch.Stop();

            Debug.WriteLine("#### String.CompareOrdinal(compare1, compare2) compare: " + stopWatch.ElapsedMilliseconds);

            stopWatch.Reset();
        }
    }
}

Ответ 5

Я проверил как string.Compare, так и string.CompareOrdinal, используя секундомер

    --Compare Ordinal  case 1 
    Stopwatch sw = new Stopwatch();
    sw.Start();
    int x = string.CompareOrdinal("Jaswant Agarwal", "Jaswant Agarwal");
    sw.Stop();
    lblTimeGap.Text = sw.Elapsed.ToString(); 






    -- Only compare  case 2
    Stopwatch sw = new Stopwatch();
    sw.Start();
    int x = string.Compare("Jaswant Agarwal", "Jaswant Agarwal");
    sw.Stop();
    lblTimeGap.Text = sw.Elapsed.ToString();

В случае 1 Среднее истекшее время было 00: 00: 00.0000030 В случае 2 Среднее истекшее время было 00: 00: 00.0000086

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

Это мое собственное наблюдение. Вы также можете попробовать просто поместить две кнопки в форму и скопировать этот код в регрессирующем событии.

Ответ 6

Это может быть полезно кому-то, но изменение одной строки моего кода привело к тестированию модуля моего метода с 140 мс до 1 мс!

Оригинал

Unit test: 140 мс

public bool StringsMatch(string string1, string string2)
{
    if (string1 == null && string2 == null) return true;
    return string1.Equals(string2, StringComparison.Ordinal);
}

New

Unit test: 1 мс

public bool StringsMatch(string string1, string string2)
{
    if (string1 == null && string2 == null) return true;
    return string.CompareOrdinal(string1, string2) == 0 ? true : false;
}

Unit Test (NUnit)

[Test]
public void StringsMatch_OnlyString1NullOrEmpty_ReturnFalse()
{
    Authentication auth = new Authentication();
    Assert.IsFalse(auth.StringsMatch(null, "foo"));
    Assert.IsFalse(auth.StringsMatch("", "foo"));
}

Интересно, что StringsMatch_OnlyString1NullOrEmpty_ReturnFalse() был единственным unit test, который использовал 140ms для метода StringsMatch. StringsMatch_AllParamsNullOrEmpty_ReturnTrue() всегда был 1ms и StringsMatch_OnlyString2NullOrEmpty_ReturnFalse() всегда < 1ms.

Ответ 7

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

Изучая эту тему немного дальше, я встретил интересный пост в блоге, в котором сравниваются все методы сравнения строк. Вероятно, не очень научный, но по-прежнему хороший номер дома.

Благодаря этой статье я начал использовать string.CompareOrdinal в сценарии, где мне приходилось выяснять, была ли одна строка в списке из 170 000 других строк и делает это 1600 раз подряд. string.CompareOrdinal сделал это почти на 50% быстрее, чем string.Equals