views:

71

answers:

5

Hi,

I'm trying to write an in-line function for count occurrences of a word in a string using lambda expressions recursively.

The function:

Func<string, string, int> getOccurrences = null;
getOccurrences = (text, searchTerm) =>
  text.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) == -1
  ? 0
  : getOccurrences(
      text.Substring(
        text.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase)
        + searchTerm.Length),
      searchTerm) + 1;

The problem is that I'm call IndexOf method twice, The first one is for recursive break condition and the second one is to get the value for add it.

Is there any suggest to call it once?

Thanks in advance.

A: 

I suggest you make it a separate method

   Func<string, string, int> getOccurrences = GetOccurrences;

   private int GetOccurrences(string text, string searchTerm)
   {
        //...    
   }

or inline

Func<string, string, int> getOccurrences = delegate(string text, string searchTerm)
                                           {
                                               //...
                                           };

with lambda syntax but just another way of writing the above

Func<string, string, int> getOccurrences = (string text, string searchTerm) =>
                                           {
                                               //...
                                           };
CRice
+6  A: 

If you don't mind a non-pure-function lambda you can do:-

Func<string, string, int> getOccurrences = null;
getOccurrences = (text, searchTerm) => 
{
   int i = text.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase);
   return i == -1 ? 0 : getOccurrences(i + searchTerm.Length), searchTerm) + 1;
}
Hightechrider
What is "non-pure" about that? (I am out of up-votes :-) It simply shows that a "non-lambda" (e.g. multiple lines in an anon-function/delegate) is a perfectly good (if not better) approach than a "pure lambda". I believe they are both compiled down the same, but have no verified this.
pst
pst: It's "non-pure" in the sense that it's a lambda that you can't make into an `Expression<Func<string, string, int>>`
Gabe
@Highttech: between the braces, is that like a delegate, then?
dboarman
A: 

You could do it like this:

Func<string, string, int> getOccurrences =
    (text, searchTerm) => getOccurrencesInternal(
        text,
        searchTerm,
        text.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase));
Func<string, string, int, int> getOccurrencesInternal = null;
getOccurrences = (text, searchTerm, index) => 
  index == -1 
  ? 0 
  : getOccurrencesInternal( 
      text.Substring( 
        index + searchTerm.Length), 
      searchTerm) + 1; 
Gabe
A: 

You could use an additional, anonymous lambda and invoke it immediately. I'm not certain of the exact C# syntax, but it should look something like:

Func<string, string, int> getOccurrences = null;
getOccurrences = (text, searchTerm) =>
  ((index) =>
    index == -1
    ? 0
    : getOccurrences(text.Substring(index + searchTerm.Length),
        searchTerm) + 1
  )(text.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase))
outis
A: 

My usual solution to these kind of problems, ignoring any optimizations, is just to remove the matching term and check any change in the resulting string's length.

Func<String, String, Int32> getOccurrences = (text, term) => 
    (text.Length - text.Replace(term, "").Length) / term.Length;
Simon Svensson