String.IndexOfAny(string, string[]) (lowest position for group of needles in haystack)
It seems that you've managed to fix the algorithm, so it does what it's supposed to do. But the concept is the same and performance isn't improved. 

Still you could use some more descriptive names, and i instead of j1 (why 1?).

You could use foreach (string target in targets) { ... } instead of for (int j1;...) because you don't use the index to anything and the performance for an array is about the same for the two for-concepts.



You ask for other algorithm types that improves performance.

One concept for the algorithm - that seems to improve the performance significantly - could be the following:

public static int IndexOfAny(this string text, params string[] targets)
{
  if (string.IsNullOrEmpty(text)) return -1;
  if (targets == null || targets.Length == 0) return -1;

  for (int i = 0; i &lt; text.Length; i++)
  {
    foreach (string target in targets)
    {
      if (i + target.Length &lt;= text.Length &amp;&amp; target == text.Substring(i, target.Length))
        return i;
    }
  }

  return -1;
}




Another that can improve performance even more is the following written in pseudo code - leaving it as a challenge for you to implement it in C#:

IndexOfAny text targets:
    for i = 0 to len(text)-1:
        skip = len(text)
        foreach target in targets:
            target_can_skip = 0
            for k = 0 to len(target)-1:
                if target[k] &lt;&gt; text[i+k]:
                    target_can_skip = count how many chars that can be skipped in text before target can be a candidate again
                    break
            if k == len(target):
                return i


            skip = min(skip, target_can_skip)

        if skip &gt; 0: 
            i = i + skip - 1

    return -1 // No match found




Besides that you may find inspiration here



Update according to VisualMelons comments:

The above implemented with string.IndexOf():

public static int IndexOfAny1(this string text, params string[] targets)
{
  if (string.IsNullOrEmpty(text)) return -1;
  if (targets == null || targets.Length == 0) return -1;

  for (int i = 0; i &lt; text.Length; i++)
  {
    foreach (string target in targets)
    {
      if (i + target.Length &lt;= text.Length &amp;&amp; text.IndexOf(target, i, target.Length) == i)
        return i;
    }
  }

  return -1;
}


Notice that the count parameter must be at minimum the length of target or else it will not be found.

Test case:

  Stopwatch watch = Stopwatch.StartNew();
  IndexOfAnyDelegate[] funcs = new IndexOfAnyDelegate[]
  {
    Extensions.IndexOfAny,
    //Extensions.IndexOfAny1,
  };

    int sum = 0;

    for (int i = 0; i &lt; 10000; i++)
    {
      foreach (var func in funcs)
      {
        sum += func("foo bar baz", "foo", "barz", "baz", " ");
        sum += func("aabbccddeeffgghh", "bbb", "hh", "aaa", "fg");
        sum += func("abcabc", "c", "abc");
        sum += func("abcabc", "x", "wer");
        sum += func("adfaææwjerqijaæsdklfjaeoirweqærqkljadfaewrwexwer", "xxxxx", "yyyyy", "zzzzz", "Aaaaaa", "x", "wer");

        //Console.WriteLine($"IndexOfAny should be 8: {func("foo bar baz", "barz", "baz", " ", "foo")}");
        //Console.WriteLine($"IndexOfAny should be 0: {func("aabbccddeeffgghh", "bbb", "hh", "aaa", "fg")}");
        //Console.WriteLine($"IndexOfAny should be 0: {func("abcabc", "c", "abc")}");
        //Console.WriteLine($"IndexOfAny should be 0: {func("abcabc", "x", "wer")}");
        //Console.WriteLine(func("adfaææwjerqijaæsdklfjaeoirweqærqkljadfaewrwexwer", "xxxxx", "yyyyy", "zzzzz", "Aaaaaa", "x", "wer"));
        //Console.WriteLine();
      }
    }
    watch.Stop();
    Console.WriteLine(sum);
    Console.WriteLine(watch.ElapsedMilliseconds);


You'll have to comment in/out as needed.



Update 2

The performance of the above pseudo code decreases (obviously) when the number of targets increases. So my analysis wasn't quite good enough. To optimize on that problem the below variant maintains an array of the next valid index per target, which minimize the number of targets that should be examined per char in the text string:

public static int IndexOfAny(this string text, params string[] targets)
{
  if (string.IsNullOrEmpty(text)) return -1;
  if (targets == null || targets.Length == 0) return -1;

  // Holds the next valid index in text per parget.
  int[] targetNextIndex = new int[targets.Length];

  for (int i = 0; i &lt; text.Length; i++)
  {
    for (int j = 0; j &lt; targets.Length; j++)
    {
      // If the targets next index isn't i then continue to next target
      if (targetNextIndex[j] &gt; i)
        continue;

      string target = targets[j];
      int k = 0;

      for (; k &lt; target.Length &amp;&amp; i + k &lt; text.Length; k++)
      {
        if (target[k] != text[i + k])
        {
          int nextIndex = i + 1;
          // Tries to find the next index in text where the char equals the first char in target.
          while (nextIndex &lt; text.Length &amp;&amp; target[0] != text[nextIndex])
          {
            nextIndex++;
          }
          // The next valid index for the target is found, so save it
          targetNextIndex[j] = nextIndex;
          break;
        }
      }

      if (k == target.Length)
      {
        return i;
      }
    }
  }

  return -1;
}