Как бы вы подсчитали вхождения строки (на самом деле char) внутри строки?
Я делаю что-то, где я понял, что хотел подсчитать, сколько /
я мог найти в строке, а затем мне показалось, что есть несколько способов сделать это, но не мог решить, какой лучший (или самый простой),
На данный момент я собираюсь с чем-то вроде:
string source = "/once/upon/a/time/";
int count = source.Length - source.Replace("/", "").Length;
Но мне это совсем не нравится, какие-то участники?
Я действительно не хочу выкапывать RegEx
для этого, не так ли?
Я знаю, что моя строка будет иметь термин, который я ищу, поэтому вы можете предположить, что...
Конечно, для строк, где длина> 1,
string haystack = "/once/upon/a/time";
string needle = "/";
int needleCount = ( haystack.Length - haystack.Replace(needle,"").Length ) / needle.Length;
Ответы
Ответ 1
Если вы используете .NET 3.5, вы можете сделать это в одном слое с LINQ:
int count = source.Count(f => f == '/');
Если вы не хотите использовать LINQ, вы можете сделать это с помощью
int count = source.Split('/').Length - 1;
Вы можете быть удивлены, узнав, что ваша оригинальная техника, кажется, примерно на 30% быстрее, чем любой из этих! Я только что сделал быстрый тест с "/once/on/a/time/", и результаты следующие:
Ваш оригинал = 12s
source.Count = 19s
source.Split = 17s
foreach (из ответа bobwienholt) = 10 с
(Время для 50 000 000 итераций, поэтому вы вряд ли заметите большую разницу в реальном мире.)
Ответ 2
string source = "/once/upon/a/time/";
int count = 0;
foreach (char c in source)
if (c == '/') count++;
Быть быстрее, чем source.Replace()
.
Ответ 3
int count = new Regex(Regex.Escape(needle)).Matches(haystack).Count;
Ответ 4
Если вы хотите иметь возможность поиска целых строк, а не только символов:
src.Select((c, i) => src.Substring(i)).Count(sub => sub.StartsWith(target))
Прочитайте как "для каждого символа в строке, возьмите оставшуюся часть строки, начиная с этого символа в качестве подстроки, посчитайте ее, если она начинается с целевой строки".
Ответ 5
Я провел некоторое исследование и обнаружил, что решение Ричарда Уотсона является самым быстрым в большинстве случаев. То, что таблица с результатами каждого решения в сообщении (кроме тех, которые используют Regex, потому что он генерирует исключения при анализе строки типа "test {test" )
Name | Short/char | Long/char | Short/short| Long/short | Long/long |
Inspite | 134| 1853| 95| 1146| 671|
LukeH_1 | 346| 4490| N/A| N/A| N/A|
LukeH_2 | 152| 1569| 197| 2425| 2171|
Bobwienholt | 230| 3269| N/A| N/A| N/A|
Richard Watson| 33| 298| 146| 737| 543|
StefanosKargas| N/A| N/A| 681| 11884| 12486|
Вы можете видеть, что в случае нахождения числа вхождений коротких подстрок (1-5 символов) в короткой строке (10-50 символов) предпочтительным является исходный алгоритм.
Кроме того, для многосимвольной подстроки вы должны использовать следующий код (на основе решения Ричарда Уотсона)
int count = 0, n = 0;
if(substring != "")
{
while ((n = source.IndexOf(substring, n, StringComparison.InvariantCulture)) != -1)
{
n += substring.Length;
++count;
}
}
Ответ 6
LINQ работает со всеми коллекциями, и поскольку строки являются всего лишь набором символов, как насчет этого симпатичного маленького однострочного интерфейса:
var count = source.Count(c => c == '/');
Убедитесь, что у вас есть using System.Linq;
в верхней части файла кода, так как .Count
- это метод расширения из этого пространства имен.
Ответ 7
Они оба работают только для односимвольных поисковых терминов...
countOccurences("the", "the answer is the answer");
int countOccurences(string needle, string haystack)
{
return (haystack.Length - haystack.Replace(needle,"").Length) / needle.Length;
}
может оказаться лучше для более длинных игл...
Но должен быть более элегантный способ.:)
Ответ 8
string source = "/once/upon/a/time/";
int count = 0;
int n = 0;
while ((n = source.IndexOf('/', n)) != -1)
{
n++;
count++;
}
На моем компьютере это примерно на 2 секунды быстрее, чем решение для каждого персонажа для 50 миллионов итераций.
Версия 2013:
Измените строку на char [] и повторите ее. Сокращает еще одну секунду или два от общего времени для итераций 50 м!
char[] testchars = source.ToCharArray();
foreach (char c in testchars)
{
if (c == '/')
count++;
}
Это еще быстрее:
char[] testchars = source.ToCharArray();
int length = testchars.Length;
for (int n = 0; n < length; n++)
{
if (testchars[n] == '/')
count++;
}
Для хорошей меры повторение с конца массива до 0 кажется самым быстрым, примерно на 5%.
int length = testchars.Length;
for (int n = length-1; n >= 0; n--)
{
if (testchars[n] == '/')
count++;
}
Мне было интересно, почему это могло быть и было Googling вокруг (я помню что-то об обратном итерации быстрей), и натолкнулся на этот вопрос, который досадно использует строку для char []. Я думаю, что трюк в обратном направлении является новым в этом контексте.
Каков самый быстрый способ перебора отдельных символов в строке на С#?
Ответ 9
Edit:
source.Split('/').Length-1
Ответ 10
Regex.Matches( Regex.Escape(input), "stringToMatch" ).Count
Ответ 11
В С# хороший счетчик String SubString - это неожиданно сложный человек:
public static int CCount(String haystack, String needle)
{
return haystack.Split(new[] { needle }, StringSplitOptions.None).Length - 1;
}
Ответ 12
string s = "65 fght 6565 4665 hjk";
int count = 0;
foreach (Match m in Regex.Matches(s, "65"))
count++;
Ответ 13
private int CountWords(string text, string word) {
int count = (text.Length - text.Replace(word, "").Length) / word.Length;
return count;
}
Поскольку исходное решение было самым быстрым для символов, я полагаю, оно также будет для строк. Итак, вот мой вклад.
В контексте: Я искал такие слова, как "failed" и "successed" в файле журнала.
Gr,
Бен
Ответ 14
Для тех, кто хочет использовать метод расширения String,
вот что я использую, основываясь на лучших опубликованных ответах:
public static class StringExtension
{
/// <summary> Returns the number of occurences of a string within a string, optional comparison allows case and culture control. </summary>
public static int Occurrences(this System.String input, string value, StringComparison stringComparisonType = StringComparison.Ordinal)
{
if (String.IsNullOrEmpty(value)) return 0;
int count = 0;
int position = 0;
while ((position = input.IndexOf(value, position, stringComparisonType)) != -1)
{
position += value.Length;
count += 1;
}
return count;
}
/// <summary> Returns the number of occurences of a single character within a string. </summary>
public static int Occurrences(this System.String input, char value)
{
int count = 0;
foreach (char c in input) if (c == value) count += 1;
return count;
}
}
Ответ 15
public static int GetNumSubstringOccurrences(string text, string search)
{
int num = 0;
int pos = 0;
if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(search))
{
while ((pos = text.IndexOf(search, pos)) > -1)
{
num ++;
pos += search.Length;
}
}
return num;
}
Ответ 16
Я думаю, что самый простой способ сделать это - использовать регулярные выражения. Таким образом, вы можете получить тот же счетчик расчётов, что и myVar.Split('x'), но с настройкой нескольких символов.
string myVar = "do this to count the number of words in my wording so that I can word it up!";
int count = Regex.Split(myVar, "word").Length;
Ответ 17
Общая функция для вхождения строк:
public int getNumberOfOccurencies(String inputString, String checkString)
{
if (checkString.Length > inputString.Length || checkString.Equals("")) { return 0; }
int lengthDifference = inputString.Length - checkString.Length;
int occurencies = 0;
for (int i = 0; i < lengthDifference; i++) {
if (inputString.Substring(i, checkString.Length).Equals(checkString)) { occurencies++; i += checkString.Length - 1; } }
return occurencies;
}
Ответ 18
string source = "/once/upon/a/time/";
int count = 0, n = 0;
while ((n = source.IndexOf('/', n) + 1) != 0) count++;
Вариант ответа Ричарда Уотсона, немного более быстрый с повышением эффективности, больше времени char происходит в строке и меньше кода!
Хотя я должен сказать, без тщательного тестирования каждого сценария, я видел очень значительное улучшение скорости, используя:
int count = 0;
for (int n = 0; n < source.Length; n++) if (source[n] == '/') count++;
Ответ 19
Строка в строке:
Найти "и т.д." в ".. JD JD JD JD и т.д. и т.д. JDJDJDJDJDJDJDJD и т.д."
var strOrigin = " .. JD JD JD JD etc. and etc. JDJDJDJDJDJDJDJD and etc.";
var searchStr = "etc";
int count = (strOrigin.Length - strOrigin.Replace(searchStr, "").Length)/searchStr.Length.
Проверяйте производительность перед тем, как отбросить это как неудобный/неуклюжий...
Ответ 20
str="aaabbbbjjja";
int count = 0;
int size = str.Length;
string[] strarray = new string[size];
for (int i = 0; i < str.Length; i++)
{
strarray[i] = str.Substring(i, 1);
}
Array.Sort(strarray);
str = "";
for (int i = 0; i < strarray.Length - 1; i++)
{
if (strarray[i] == strarray[i + 1])
{
count++;
}
else
{
count++;
str = str + strarray[i] + count;
count = 0;
}
}
count++;
str = str + strarray[strarray.Length - 1] + count;
Это для подсчета появления символа. Для этого примера вывод будет "a4b4j3"
Ответ 21
string Name = "Very good nice one is very good but is very good nice one this is called the term";
bool valid=true;
int count = 0;
int k=0;
int m = 0;
while (valid)
{
k = Name.Substring(m,Name.Length-m).IndexOf("good");
if (k != -1)
{
count++;
m = m + k + 4;
}
else
valid = false;
}
Console.WriteLine(count + " Times accures");
Ответ 22
var conditionalStatement = conditionSetting.Value;
//order of replace matters, remove == before =, incase of ===
conditionalStatement = conditionalStatement.Replace("==", "~").Replace("!=", "~").Replace('=', '~').Replace('!', '~').Replace('>', '~').Replace('<', '~').Replace(">=", "~").Replace("<=", "~");
var listOfValidConditions = new List<string>() { "!=", "==", ">", "<", ">=", "<=" };
if (conditionalStatement.Count(x => x == '~') != 1)
{
result.InvalidFieldList.Add(new KeyFieldData(batch.DECurrentField, "The IsDoubleKeyCondition does not contain a supported conditional statement. Contact System Administrator."));
result.Status = ValidatorStatus.Fail;
return result;
}
Нужно сделать что-то подобное тестовым условным операторам из строки.
Заменили то, что я искал с помощью одного символа, и подсчитал экземпляры одного символа.
Очевидно, что один символ, который вы используете, должен быть проверен, чтобы не существовать в строке, прежде чем это произойдет, чтобы избежать неправильного подсчета.
Ответ 23
string s = "HOWLYH THIS ACTUALLY WORKSH WOWH";
int count = 0;
for (int i = 0; i < s.Length; i++)
if (s[i] == 'H') count++;
Он просто проверяет каждый символ в строке, если символ является символом, который вы ищете, добавьте его для подсчета.
Ответ 24
Если вы проверьте эту веб-страницу, 15 различных способов сделать это сравниваются, включая использование параллельных циклов.
Самый быстрый способ, по-видимому, заключается в использовании одного потока для цикла (если у вас есть .Net версия < 4.0) или цикл parallel.for(при использовании .Net > 4.0 с тысячами проверок).
Предполагая, что "ss" - это ваша строка поиска, "ch" - это ваш массив символов (если у вас есть более одного char, который вы ищете), здесь основной смысл кода, который имел самое быстрое время выполнения single резьбовое:
for (int x = 0; x < ss.Length; x++)
{
for (int y = 0; y < ch.Length; y++)
{
for (int a = 0; a < ss[x].Length; a++ )
{
if (ss[x][a] == ch[y])
//it found. DO what you need to here.
}
}
}
Исходный код теста также предоставляется, чтобы вы могли запускать собственные тесты.
Ответ 25
Думал, что я брошу свой метод расширения на ринг (см. комментарии для получения дополнительной информации). Я не делал никаких официальных проверок, но я думаю, что для большинства сценариев это должно быть очень быстро.
EDIT: ОК - поэтому этот вопрос помог мне понять, как производительность нашей текущей реализации будет складываться против некоторых из представленных здесь решений. Я решил сделать небольшую заметку и нашел, что наше решение в значительной степени соответствует производительности решения, предоставленного Ричардом Уотсоном, до тех пор, пока вы не начнете агрессивный поиск с большими строками (100 Kb +), большими подстроками (32 Kb + ) и много встроенных повторений (10K +). В этот момент наше решение было примерно в 2X-4 раза медленнее. Учитывая это и тот факт, что нам действительно нравится решение, представленное Ричардом Уотсоном, мы соответствующим образом реорганизовали наше решение. Я просто хотел сделать это доступным для всех, кто мог бы извлечь из этого выгоду.
Наше оригинальное решение:
/// <summary>
/// Counts the number of occurrences of the specified substring within
/// the current string.
/// </summary>
/// <param name="s">The current string.</param>
/// <param name="substring">The substring we are searching for.</param>
/// <param name="aggressiveSearch">Indicates whether or not the algorithm
/// should be aggressive in its search behavior (see Remarks). Default
/// behavior is non-aggressive.</param>
/// <remarks>This algorithm has two search modes - aggressive and
/// non-aggressive. When in aggressive search mode (aggressiveSearch =
/// true), the algorithm will try to match at every possible starting
/// character index within the string. When false, all subsequent
/// character indexes within a substring match will not be evaluated.
/// For example, if the string was 'abbbc' and we were searching for
/// the substring 'bb', then aggressive search would find 2 matches
/// with starting indexes of 1 and 2. Non aggressive search would find
/// just 1 match with starting index at 1. After the match was made,
/// the non aggressive search would attempt to make it next match
/// starting at index 3 instead of 2.</remarks>
/// <returns>The count of occurrences of the substring within the string.</returns>
public static int CountOccurrences(this string s, string substring,
bool aggressiveSearch = false)
{
// if s or substring is null or empty, substring cannot be found in s
if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(substring))
return 0;
// if the length of substring is greater than the length of s,
// substring cannot be found in s
if (substring.Length > s.Length)
return 0;
var sChars = s.ToCharArray();
var substringChars = substring.ToCharArray();
var count = 0;
var sCharsIndex = 0;
// substring cannot start in s beyond following index
var lastStartIndex = sChars.Length - substringChars.Length;
while (sCharsIndex <= lastStartIndex)
{
if (sChars[sCharsIndex] == substringChars[0])
{
// potential match checking
var match = true;
var offset = 1;
while (offset < substringChars.Length)
{
if (sChars[sCharsIndex + offset] != substringChars[offset])
{
match = false;
break;
}
offset++;
}
if (match)
{
count++;
// if aggressive, just advance to next char in s, otherwise,
// skip past the match just found in s
sCharsIndex += aggressiveSearch ? 1 : substringChars.Length;
}
else
{
// no match found, just move to next char in s
sCharsIndex++;
}
}
else
{
// no match at current index, move along
sCharsIndex++;
}
}
return count;
}
И вот наше исправленное решение:
/// <summary>
/// Counts the number of occurrences of the specified substring within
/// the current string.
/// </summary>
/// <param name="s">The current string.</param>
/// <param name="substring">The substring we are searching for.</param>
/// <param name="aggressiveSearch">Indicates whether or not the algorithm
/// should be aggressive in its search behavior (see Remarks). Default
/// behavior is non-aggressive.</param>
/// <remarks>This algorithm has two search modes - aggressive and
/// non-aggressive. When in aggressive search mode (aggressiveSearch =
/// true), the algorithm will try to match at every possible starting
/// character index within the string. When false, all subsequent
/// character indexes within a substring match will not be evaluated.
/// For example, if the string was 'abbbc' and we were searching for
/// the substring 'bb', then aggressive search would find 2 matches
/// with starting indexes of 1 and 2. Non aggressive search would find
/// just 1 match with starting index at 1. After the match was made,
/// the non aggressive search would attempt to make it next match
/// starting at index 3 instead of 2.</remarks>
/// <returns>The count of occurrences of the substring within the string.</returns>
public static int CountOccurrences(this string s, string substring,
bool aggressiveSearch = false)
{
// if s or substring is null or empty, substring cannot be found in s
if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(substring))
return 0;
// if the length of substring is greater than the length of s,
// substring cannot be found in s
if (substring.Length > s.Length)
return 0;
int count = 0, n = 0;
while ((n = s.IndexOf(substring, n, StringComparison.InvariantCulture)) != -1)
{
if (aggressiveSearch)
n++;
else
n += substring.Length;
count++;
}
return count;
}
Ответ 26
string search = "/string";
var occurrences = (regex.Match(search, @"\/")).Count;
Это будет отсчитываться каждый раз, когда программа находит "/s" точно (с учетом регистра) и
число вхождений этого будет сохранено в переменной "вхождения"
Ответ 27
Мой первоначальный взнос дал мне что-то вроде:
public static int CountOccurrences(string original, string substring)
{
if (string.IsNullOrEmpty(substring))
return 0;
if (substring.Length == 1)
return CountOccurrences(original, substring[0]);
if (string.IsNullOrEmpty(original) ||
substring.Length > original.Length)
return 0;
int substringCount = 0;
for (int charIndex = 0; charIndex < original.Length; charIndex++)
{
for (int subCharIndex = 0, secondaryCharIndex = charIndex; subCharIndex < substring.Length && secondaryCharIndex < original.Length; subCharIndex++, secondaryCharIndex++)
{
if (substring[subCharIndex] != original[secondaryCharIndex])
goto continueOuter;
}
if (charIndex + substring.Length > original.Length)
break;
charIndex += substring.Length - 1;
substringCount++;
continueOuter:
;
}
return substringCount;
}
public static int CountOccurrences(string original, char @char)
{
if (string.IsNullOrEmpty(original))
return 0;
int substringCount = 0;
for (int charIndex = 0; charIndex < original.Length; charIndex++)
if (@char == original[charIndex])
substringCount++;
return substringCount;
}
Игла в подходе сена с использованием замены и деления дает 21 + секунд, тогда как это занимает около 15,2.
Отредактируйте после добавления бит, который добавит substring.Length - 1
в charIndex (как и должно быть), через 11.6 секунд.
Изменить 2: я использовал строку, в которой было 26 двухсимвольных строк, здесь приведены времена, обновленные до тех же самых текстов:
Игла в стоге сена (версия OP): 7.8 секунды
Предлагаемый механизм: 4.6 секунды.
Редактирование 3: добавление одиночного символьного углового фрейма, оно продолжалось до 1,2 секунды.
Изменить 4: Для контекста: использовалось 50 миллионов итераций.
Ответ 28
В случае строкового разделителя (не для случая char, как говорит предмет):
string source = "@@@once @@@on @@@a @@@time @@@";
int count = source.Split(new [] { "@@@" }, StringSplitOptions.RemoveEmptyEntries).Length - 1;
Исходное исходное значение плаката ( "/once/on/a/time/" ) естественным разделителем является char '/', и ответы действительно объясняют параметр source.Split(char []), хотя...
Ответ 29
Я чувствовал, что нам не хватало определенных видов подсчета подстрок, таких как небезопасные побайтовые сравнения. Я собрал оригинальный метод постера и любые методы, которые могли придумать.
Это расширения строк, которые я сделал.
namespace Example
{
using System;
using System.Text;
public static class StringExtensions
{
public static int CountSubstr(this string str, string substr)
{
return (str.Length - str.Replace(substr, "").Length) / substr.Length;
}
public static int CountSubstr(this string str, char substr)
{
return (str.Length - str.Replace(substr.ToString(), "").Length);
}
public static int CountSubstr2(this string str, string substr)
{
int substrlen = substr.Length;
int lastIndex = str.IndexOf(substr, 0, StringComparison.Ordinal);
int count = 0;
while (lastIndex != -1)
{
++count;
lastIndex = str.IndexOf(substr, lastIndex + substrlen, StringComparison.Ordinal);
}
return count;
}
public static int CountSubstr2(this string str, char substr)
{
int lastIndex = str.IndexOf(substr, 0);
int count = 0;
while (lastIndex != -1)
{
++count;
lastIndex = str.IndexOf(substr, lastIndex + 1);
}
return count;
}
public static int CountChar(this string str, char substr)
{
int length = str.Length;
int count = 0;
for (int i = 0; i < length; ++i)
if (str[i] == substr)
++count;
return count;
}
public static int CountChar2(this string str, char substr)
{
int count = 0;
foreach (var c in str)
if (c == substr)
++count;
return count;
}
public static unsafe int CountChar3(this string str, char substr)
{
int length = str.Length;
int count = 0;
fixed (char* chars = str)
{
for (int i = 0; i < length; ++i)
if (*(chars + i) == substr)
++count;
}
return count;
}
public static unsafe int CountChar4(this string str, char substr)
{
int length = str.Length;
int count = 0;
fixed (char* chars = str)
{
for (int i = length - 1; i >= 0; --i)
if (*(chars + i) == substr)
++count;
}
return count;
}
public static unsafe int CountSubstr3(this string str, string substr)
{
int length = str.Length;
int substrlen = substr.Length;
int count = 0;
fixed (char* strc = str)
{
fixed (char* substrc = substr)
{
int n = 0;
for (int i = 0; i < length; ++i)
{
if (*(strc + i) == *(substrc + n))
{
++n;
if (n == substrlen)
{
++count;
n = 0;
}
}
else
n = 0;
}
}
}
return count;
}
public static int CountSubstr3(this string str, char substr)
{
return CountSubstr3(str, substr.ToString());
}
public static unsafe int CountSubstr4(this string str, string substr)
{
int length = str.Length;
int substrLastIndex = substr.Length - 1;
int count = 0;
fixed (char* strc = str)
{
fixed (char* substrc = substr)
{
int n = substrLastIndex;
for (int i = length - 1; i >= 0; --i)
{
if (*(strc + i) == *(substrc + n))
{
if (--n == -1)
{
++count;
n = substrLastIndex;
}
}
else
n = substrLastIndex;
}
}
}
return count;
}
public static int CountSubstr4(this string str, char substr)
{
return CountSubstr4(str, substr.ToString());
}
}
}
Вслед за тестовым кодом...
static void Main()
{
const char matchA = '_';
const string matchB = "and";
const string matchC = "muchlongerword";
const string testStrA = "_and_d_e_banna_i_o___pfasd__and_d_e_banna_i_o___pfasd_";
const string testStrB = "and sdf and ans andeians andano ip and and sdf and ans andeians andano ip and";
const string testStrC =
"muchlongerword amuchlongerworsdfmuchlongerwordsdf jmuchlongerworijv muchlongerword sdmuchlongerword dsmuchlongerword";
const int testSize = 1000000;
Console.WriteLine(testStrA.CountSubstr('_'));
Console.WriteLine(testStrA.CountSubstr2('_'));
Console.WriteLine(testStrA.CountSubstr3('_'));
Console.WriteLine(testStrA.CountSubstr4('_'));
Console.WriteLine(testStrA.CountChar('_'));
Console.WriteLine(testStrA.CountChar2('_'));
Console.WriteLine(testStrA.CountChar3('_'));
Console.WriteLine(testStrA.CountChar4('_'));
Console.WriteLine(testStrB.CountSubstr("and"));
Console.WriteLine(testStrB.CountSubstr2("and"));
Console.WriteLine(testStrB.CountSubstr3("and"));
Console.WriteLine(testStrB.CountSubstr4("and"));
Console.WriteLine(testStrC.CountSubstr("muchlongerword"));
Console.WriteLine(testStrC.CountSubstr2("muchlongerword"));
Console.WriteLine(testStrC.CountSubstr3("muchlongerword"));
Console.WriteLine(testStrC.CountSubstr4("muchlongerword"));
var timer = new Stopwatch();
timer.Start();
for (int i = 0; i < testSize; ++i)
testStrA.CountSubstr(matchA);
timer.Stop();
Console.WriteLine("CS1 chr: " + timer.Elapsed.TotalMilliseconds + "ms");
timer.Restart();
for (int i = 0; i < testSize; ++i)
testStrB.CountSubstr(matchB);
timer.Stop();
Console.WriteLine("CS1 and: " + timer.Elapsed.TotalMilliseconds + "ms");
timer.Restart();
for (int i = 0; i < testSize; ++i)
testStrC.CountSubstr(matchC);
timer.Stop();
Console.WriteLine("CS1 mlw: " + timer.Elapsed.TotalMilliseconds + "ms");
timer.Restart();
for (int i = 0; i < testSize; ++i)
testStrA.CountSubstr2(matchA);
timer.Stop();
Console.WriteLine("CS2 chr: " + timer.Elapsed.TotalMilliseconds + "ms");
timer.Restart();
for (int i = 0; i < testSize; ++i)
testStrB.CountSubstr2(matchB);
timer.Stop();
Console.WriteLine("CS2 and: " + timer.Elapsed.TotalMilliseconds + "ms");
timer.Restart();
for (int i = 0; i < testSize; ++i)
testStrC.CountSubstr2(matchC);
timer.Stop();
Console.WriteLine("CS2 mlw: " + timer.Elapsed.TotalMilliseconds + "ms");
timer.Restart();
for (int i = 0; i < testSize; ++i)
testStrA.CountSubstr3(matchA);
timer.Stop();
Console.WriteLine("CS3 chr: " + timer.Elapsed.TotalMilliseconds + "ms");
timer.Restart();
for (int i = 0; i < testSize; ++i)
testStrB.CountSubstr3(matchB);
timer.Stop();
Console.WriteLine("CS3 and: " + timer.Elapsed.TotalMilliseconds + "ms");
timer.Restart();
for (int i = 0; i < testSize; ++i)
testStrC.CountSubstr3(matchC);
timer.Stop();
Console.WriteLine("CS3 mlw: " + timer.Elapsed.TotalMilliseconds + "ms");
timer.Restart();
for (int i = 0; i < testSize; ++i)
testStrA.CountSubstr4(matchA);
timer.Stop();
Console.WriteLine("CS4 chr: " + timer.Elapsed.TotalMilliseconds + "ms");
timer.Restart();
for (int i = 0; i < testSize; ++i)
testStrB.CountSubstr4(matchB);
timer.Stop();
Console.WriteLine("CS4 and: " + timer.Elapsed.TotalMilliseconds + "ms");
timer.Restart();
for (int i = 0; i < testSize; ++i)
testStrC.CountSubstr4(matchC);
timer.Stop();
Console.WriteLine("CS4 mlw: " + timer.Elapsed.TotalMilliseconds + "ms");
timer.Restart();
for (int i = 0; i < testSize; ++i)
testStrA.CountChar(matchA);
timer.Stop();
Console.WriteLine("CC1 chr: " + timer.Elapsed.TotalMilliseconds + "ms");
timer.Restart();
for (int i = 0; i < testSize; ++i)
testStrA.CountChar2(matchA);
timer.Stop();
Console.WriteLine("CC2 chr: " + timer.Elapsed.TotalMilliseconds + "ms");
timer.Restart();
for (int i = 0; i < testSize; ++i)
testStrA.CountChar3(matchA);
timer.Stop();
Console.WriteLine("CC3 chr: " + timer.Elapsed.TotalMilliseconds + "ms");
timer.Restart();
for (int i = 0; i < testSize; ++i)
testStrA.CountChar4(matchA);
timer.Stop();
Console.WriteLine("CC4 chr: " + timer.Elapsed.TotalMilliseconds + "ms");
}
Результаты: CSX соответствует CountSubstrX, а CCX соответствует CountCharX. "chr" ищет строку для "_", "и" ищет строку для "and", а "mlw" ищет строку для "muchlongerword"
CS1 chr: 824.123ms
CS1 and: 586.1893ms
CS1 mlw: 486.5414ms
CS2 chr: 127.8941ms
CS2 and: 806.3918ms
CS2 mlw: 497.318ms
CS3 chr: 201.8896ms
CS3 and: 124.0675ms
CS3 mlw: 212.8341ms
CS4 chr: 81.5183ms
CS4 and: 92.0615ms
CS4 mlw: 116.2197ms
CC1 chr: 66.4078ms
CC2 chr: 64.0161ms
CC3 chr: 65.9013ms
CC4 chr: 65.8206ms
И, наконец, у меня был файл с 3,6 миллионами символов. Это был "derp adfderdserp dfaerpderp deasderp", повторенный 100 000 раз. Я искал "derp" внутри файла с помощью описанных выше методов 100 раз эти результаты.
CS1Derp: 1501.3444ms
CS2Derp: 1585.797ms
CS3Derp: 376.0937ms
CS4Derp: 271.1663ms
Так что мой 4-й метод определенно является победителем, но на самом деле, если файл с 3,6 миллионами символов 100 раз потребовал всего 1586мс как худший случай, то все это довольно незначительно.
Кстати, я также отсканировал символ 'd' в 3,6-миллионном символьном файле со 100-кратными методами CountSubstr и CountChar. Результаты...
CS1 d : 2606.9513ms
CS2 d : 339.7942ms
CS3 d : 960.281ms
CS4 d : 233.3442ms
CC1 d : 302.4122ms
CC2 d : 280.7719ms
CC3 d : 299.1125ms
CC4 d : 292.9365ms
Исходя из этого, оригинальный метод постеров очень плох для односимвольных игл в большом стоге сена.
Примечание. Все значения были обновлены до версии выпуска. Я случайно забыл использовать режим Release при первой публикации этого сообщения. Некоторые из моих заявлений были изменены.