c# एक स्ट्रिंग के भीतर आप एक स्ट्रिंग(वास्तव में एक char) की घटनाओं की गणना कैसे करेंगे?




string (23)

मैं ऐसा कुछ कर रहा हूं जहां मुझे एहसास हुआ कि मैं गिनना चाहता था कि मैं एक स्ट्रिंग में कितने / मिल सकता था, और फिर उसने मुझे मारा, कि ऐसा करने के कई तरीके थे, लेकिन यह तय नहीं कर सका कि सबसे अच्छा (या सबसे आसान) था।

फिलहाल मैं कुछ इस तरह से जा रहा हूं:

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;

string s = "HOWLYH THIS ACTUALLY WORKSH WOWH";
int count = 0;
for (int i = 0; i < s.Length; i++)
   if (s[i] == 'H') count++;

यह स्ट्रिंग में हर चरित्र की जांच करता है, अगर चरित्र वह चरित्र है जिसे आप खोज रहे हैं, तो गिनने के लिए एक जोड़ें।


यदि आप इस वेबपृष्ठ को देखते हैं , तो ऐसा करने के 15 अलग-अलग तरीके समानांतर लूप का उपयोग करके बेंचमार्क किए गए हैं।

सबसे तेज़ तरीका या तो एक थ्रेडेड फॉर-लूप (यदि आपके पास .Net संस्करण <4.0) है या समानांतर है। लूप (यदि हजारों चेक के साथ .NET> 4.0 का उपयोग कर रहे हैं) का उपयोग करना प्रतीत होता है।

मान लें कि "एसएस" आपकी खोज स्ट्रिंग है, "सी" आपका चरित्र सरणी है (यदि आपके पास एक से अधिक char हैं जो आप ढूंढ रहे हैं), यहां कोड का मूल आधार है जिसमें सबसे तेज़ रन टाइम सिंगल थ्रेडेड था:

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's found. DO what you need to here.
        }
    }
}

बेंचमार्क स्रोत कोड भी प्रदान किया जाता है ताकि आप अपने स्वयं के परीक्षण चला सकें।


string source = "/once/upon/a/time/";
int count = 0;
int n = 0;

while ((n = source.IndexOf('/', n)) != -1)
{
   n++;
   count++;
}

मेरे कंप्यूटर पर यह 50 मिलियन पुनरावृत्तियों के लिए हर-चरित्र समाधान की तुलना में लगभग 2 सेकंड तेज है।

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

मैं सोच रहा था कि यह क्यों हो सकता है और चारों ओर गुगलिंग कर रहा था (मुझे रिवर्स पुनरावृत्ति के बारे में कुछ याद आ रहा है), और इस SO सवाल पर आया जो कष्टप्रद रूप से तार [] तकनीक को स्ट्रिंग का उपयोग करता है। मुझे लगता है कि रिवर्सल चाल इस संदर्भ में नई है, हालांकि।

C # में स्ट्रिंग में अलग-अलग वर्णों के माध्यम से पुनरावृत्ति करने का सबसे तेज़ तरीका क्या है?


मुझे लगता है कि ऐसा करने का सबसे आसान तरीका नियमित अभिव्यक्तियों का उपयोग करना है। इस तरह आप एक ही विभाजित गणना प्राप्त कर सकते हैं क्योंकि आप 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;

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");

LINQ सभी संग्रहों पर काम करता है, और चूंकि तार केवल वर्णों का संग्रह हैं, इस छोटे से छोटे-लाइनर के बारे में कैसे:

var count = source.Count(c => c == '/');

सुनिश्चित करें कि आपने using System.Linq; आपकी कोड फ़ाइल के शीर्ष पर, जैसे। .Count उस नामस्थान से एक एक्सटेंशन विधि है।


यदि आप .NET 3.5 का उपयोग कर रहे हैं तो आप LINQ के साथ एक-लाइनर में ऐसा कर सकते हैं:

int count = source.Count(f => f == '/');

यदि आप LINQ का उपयोग नहीं करना चाहते हैं तो आप इसे इसके साथ कर सकते हैं:

int count = source.Split('/').Length - 1;

आप यह जानकर आश्चर्यचकित हो सकते हैं कि आपकी मूल तकनीक इनमें से किसी भी की तुलना में लगभग 30% तेज है! मैंने अभी "/ one / upon / a / time /" के साथ त्वरित बेंचमार्क किया है और परिणाम निम्नानुसार हैं:

आपका मूल = 12 एस
स्रोत। गणना = 1 9
स्रोत। स्प्लिट = 17 एस
foreach ( बॉबवियनहोल्ट के जवाब से ) = 10 एस

(समय 50,000,000 पुनरावृत्तियों के लिए है, इसलिए वास्तविक दुनिया में आपको बहुत अंतर दिखाई देने की संभावना नहीं है।)


string search = "/string";
var occurrences = (regex.Match(search, @"\/")).Count;

यह हर बार गिनती करेगा जब कार्यक्रम "/ एस" बिल्कुल (केस संवेदनशील) पाता है और इसकी घटनाओं की संख्या परिवर्तनीय "घटनाओं" में संग्रहीत की जाएगी


private int CountWords(string text, string word) {
    int count = (text.Length - text.Replace(word, "").Length) / word.Length;
    return count;
}

चूंकि मूल समाधान, वर्णों के लिए सबसे तेज़ था, मुझे लगता है कि यह तारों के लिए भी होगा। तो मेरा योगदान यहाँ है।

संदर्भ के लिए: मैं लॉग फ़ाइल में 'विफल' और 'सफल' जैसे शब्दों की तलाश में था।

जीआर, बेन


स्ट्रिंग डेलीमीटर के मामले में (चार मामले के लिए नहीं, जैसा कि विषय कहता है):
स्ट्रिंग स्रोत = "@@@ एक बार @@@ @@@@@@@@@@@@@@@@@@@@ @
int गिनती = स्रोत। स्प्लिट (नया [] {"@@@"}, स्ट्रिंगस्प्लिटऑप्शन। रीमूवइएक्ट्रीइन्ट्रीज़)। लम्बाई - 1;

पोस्टर का मूल स्रोत मान ("/ एक बार / एक / समय /") प्राकृतिक डेलीमीटर एक चार '/' है और प्रतिक्रिया स्रोत को समझाती है। स्प्लिट (char []) विकल्प हालांकि ...


संपादित करें:

source.Split('/').Length-1

सी # में, एक अच्छा स्ट्रिंग सबस्ट्रिंग काउंटर यह अप्रत्याशित रूप से मुश्किल साथी है:

public static int CCount(String haystack, String needle)
{
    return haystack.Split(new[] { needle }, StringSplitOptions.None).Length - 1;
}

यदि आप पूरे तारों की खोज करने में सक्षम होना चाहते हैं, न कि केवल वर्ण:

src.Select((c, i) => src.Substring(i)).Count(sub => sub.StartsWith(target))

स्ट्रिंग में प्रत्येक वर्ण के लिए "उस वर्ण से शुरू होने वाली शेष स्ट्रिंग को एक सबस्ट्रिंग के रूप में पढ़ें; इसे लक्ष्य स्ट्रिंग के साथ शुरू होने पर गिनें।"


int count = new Regex(Regex.Escape(needle)).Matches(haystack).Count;

स्ट्रिंग एक्सटेंशन विधि का उपयोग करने के लिए तैयार किसी के लिए,

यहां मैं जो उपयोग करता हूं वह पोस्ट किए गए उत्तरों के सर्वोत्तम पर आधारित था:

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

string source = "/once/upon/a/time/";
int count = 0, n = 0;
while ((n = source.IndexOf('/', n) + 1) != 0) count++;

रिचर्ड वाटसन के जवाब पर एक बदलाव, दक्षता में सुधार के साथ थोड़ा तेज़ स्ट्रिंग में चार बार होता है, और कम कोड!

हालांकि मुझे कहना होगा कि, हर परिदृश्य का व्यापक परीक्षण किए बिना, मैंने इसका उपयोग करके एक बहुत ही महत्वपूर्ण गति सुधार देखा:

int count = 0;
for (int n = 0; n < source.Length; n++) if (source[n] == '/') count++;

Regex.Matches( Regex.Escape(input),  "stringToMatch" ).Count

स्ट्रिंग में स्ट्रिंग:

"आदि" में खोजें ".. जेडी जेडी जेडी जेडी आदि आदि। जेडीजेडीजेडीजेडीजेडीजेडीजेडीजेडी और आदि"

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.

इसे किसी को अस्वस्थ / बेकार के रूप में हटाने से पहले प्रदर्शन की जांच करें ...


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

मेरे शुरुआती लेते ने मुझे कुछ दिया:

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 जोड़ देगा। तरंग substring.Length - 1 charIndex (जैसे यह चाहिए), यह 11.6 सेकंड पर है।

संपादित करें 2: मैंने एक स्ट्रिंग का उपयोग किया जिसमें 26 दो-वर्ण तार थे, यहां एक ही नमूना ग्रंथों में अपडेट किए गए समय हैं:

एक घास में सुई (ओपी का संस्करण): 7.8 सेकेंड

सुझाया गया तंत्र: 4.6 सेकंड।

संपादित करें 3: एकल वर्ण कोने-केस जोड़ना, यह 1.2 सेकंड तक चला गया।

संपादित करें 4: संदर्भ के लिए: 50 मिलियन पुनरावृत्तियों का उपयोग किया गया था।


मैंने कुछ शोध किया है और पाया है कि ज्यादातर मामलों में रिचर्ड वाटसन का समाधान सबसे तेज़ है। पोस्ट में प्रत्येक समाधान के परिणाम के साथ यह तालिका है (उनको छोड़कर रेगेक्स का उपयोग करें क्योंकि यह "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|

आप देख सकते हैं कि शॉर्ट स्ट्रिंग (10-50 वर्ण) में शॉर्ट सबस्ट्रिंग्स (1-5 वर्ण) के अवसरों की संख्या खोजने के मामले में मूल एल्गोरिदम को प्राथमिकता दी जाती है।

इसके अलावा, मल्टीचार्टर सबस्ट्रिंग के लिए आपको निम्न कोड का उपयोग करना चाहिए ( रिचर्ड वाटसन के समाधान के आधार पर)

int count = 0, n = 0;

if(substring != "")
{
    while ((n = source.IndexOf(substring, n, StringComparison.InvariantCulture)) != -1)
    {
        n += substring.Length;
        ++count;
    }
}

string source = "/once/upon/a/time/";
int count = 0;
foreach (char c in source) 
  if (c == '/') count++;

source.Replace() से तेज़ होना चाहिए। अपने आप को source.Replace()


तारों की घटनाओं के लिए एक सामान्य कार्य:

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




string