-1

So i have this C# code:

static void Main(string[] args)
{            
   string @string = "- hello dude! - oh hell yeah hey what's up guy";

   Console.WriteLine(String.Join(".", @string.GetSubstringsIndexes("he")));
   Console.Read();
}

partial class that adds an extension "GetSubstringsIndexes" method:

partial class StringExtension
{
    public static int[] GetSubstringsIndexes(this string @string, string substring)
    {
        List<int> indexes = new List<int>(@string.Length / substring.Length);

        int result = @string.IndexOf(substring, 0);
        while (result >= 0)
        {
            indexes.Add(result);
            result = @string.IndexOf(substring, result + substring.Length);
        }

        return indexes.ToArray();
    }
}

What i would want it to be like, is a lambda expression in the parameters brackets of a String.Join method instead of calling a function i wrote.

I mean, i would just want not to write this function and THEN call it, but to write a lambda expression to use only once!

Example of how i would want it to look like:

static void Main(string[] args)
{            
   string @string = "- hello dude! - oh hell yeah hey what's up guy";

   Console.WriteLine(String.Join(".", () => {List<int> ind = new List<int>()..... AND SO ON...} ));
   Console.Read();
}

Well, actually, I've just realized (while writing this question) that for this kind of a situation it is unnecessary, because my GetSubStringsIndexes method is too big. But imagine if it were a short one.

Just tell me whether or not it is possible to do something like that, and if it is possible, please, tell me how!

Edit:

I've done it and that's how it looks like:

        Console.WriteLine(String.Join(".", ((Func<int[]>)
            ( () => 
            {
                List<int> indx = new List<int>();
                int res = @string.IndexOf("he", 0);
                while (res >= 0)
                {
                    indx.Add(res);
                    res = @string.IndexOf("he", res + "he".Length);
                }
                return indx.ToArray();
            }
            ))()));

4 Answers4

1

Your "improvement" in the question works. Here is a more concise way of doing that with a helper function that you need to define only once:

static void Execute<TReturn>(Func<TReturn> func) => func();

Then:

Console.WriteLine(Execute(() => { /* any code here */ }));

This infers the delegate type automatically and calls the delegate. This removes a lot of clutter.

In general I'd advise against this style. Use multiple lines of code instead.

usr
  • 168,620
  • 35
  • 240
  • 369
0

What you want isn't possible, as String.join() doesn't accept a Func<int[]> or an Expression<Func<int[]>>.

You could use a local function and call that, if you don't want to write an extension method.

static void Main(string[] args)
{            
   string @string = "- hello dude! - oh hell yeah hey what's up guy";

   Console.WriteLine(String.Join(".", GetIndexes('he'));
   Console.Read();

   int[] GetIndexes(string substring) {
       var indexes = new List<int>();
       // compute indexes as desired. @string is available here.
       return indexes.ToArray();
   }
}
0

One way to do it would be to use a Select statement where you capture both the character being examined and it's index in the string (using the syntax: Select((item, index) => ...), and then, if the substring exists at that index, return the index, otherwise return -1 (from the Select statement), and then follow that up with a Where clause to remove any -1 results.

The code is a little long because we also have to be sure that we aren't too close to the end of the string before we check the substring (which results in another ternary condition that returns -1).

I'm sure this can be improved, but it's a start:

string @string = "- hello dude! - oh hell yeah hey what's up guy";           

var subString = "he";

Console.WriteLine(string.Join(".", @string.Select((chr, index) =>
    index + subString.Length < @string.Length
        ? @string.Substring(index, subString.Length) == subString
            ? index
            : -1
        : -1)
    .Where(result => result > -1)));

In case that's too hard to read (due to the multiple ?: ternary expressions), here it is with comments before each line:

// For each character in the string, grab the character and it's index
Console.WriteLine(string.Join(".", @string.Select((chr, index) =>
    // If we're not too close to the end of the string
    index + subString.Length < @string.Length
        // And the substring exists at this index          
        ? @string.Substring(index, subString.Length) == subString
            // Return this index
            ? index
            // Substring not found here; return -1
            : -1
        // We're too close to end; return -1
        : -1) 
    // Return only the indexes where the substring was found
    .Where(result => result > -1)));
Rufus L
  • 36,127
  • 5
  • 30
  • 43
0

The final result:

Console.WriteLine(String.Join(".", ((Func<int[]>)
    ( () => 
    {
        List<int> indx = new List<int>();
        int res = @string.IndexOf("he", 0);
        while (res >= 0)
        {
            indx.Add(res);
            res = @string.IndexOf("he", res + "he".Length);
        }
        return indx.ToArray();
    }
))()));