Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a String.IndexOf that takes a predicate?

Tags:

c#

.net

linq

I need to be able to say something like myString.IndexOf(c => !Char.IsDigit(c)), but I can't find any such method in the .NET framework. Did I miss something?

The following works, but rolling my own seems a little tedious here:

using System;

class Program
{
    static void Main()
    {
        string text = "555ttt555";
        int nonDigitIndex = text.IndexOf(c => !Char.IsDigit(c));
        Console.WriteLine(nonDigitIndex);
    }
}

static class StringExtensions
{
    public static int IndexOf(this string self, Predicate<char> predicate)
    {
        for (int index = 0; index < self.Length; ++index) {
            if (predicate(self[index])) {
                return index;
            }
        }
        return -1;
    }
}
like image 953
Tom Avatar asked Sep 14 '11 17:09

Tom


People also ask

Which is faster IndexOf or contains?

IndexOf(string) has no options and Contains() uses an Ordinal compare (a byte-by-byte comparison rather than trying to perform a smart compare, for example, e with é). So IndexOf will be marginally faster (in theory) as IndexOf goes straight to a string search using FindNLSString from kernel32.

What does .IndexOf do in Java?

Definition and Usage The indexOf() method returns the position of the first occurrence of specified character(s) in a string. Tip: Use the lastIndexOf method to return the position of the last occurrence of specified character(s) in a string.

How do you find first occurrence of a character in a string Javascript?

The indexOf() method returns the position of the first occurrence of a value in a string. The indexOf() method returns -1 if the value is not found. The indexOf() method is case sensitive.

Can you index a string in C#?

In C#, IndexOf() method is a string method. This method is used to find the zero-based index of the first occurrence of a specified character or string within the current instance of the string. The method returns -1 if the character or string is not found.


2 Answers

Your current solution is better but could do something like ...

int c = myString.TakeWhile(c => Char.IsDigit(c)).Count();
return (c == myString.Length) ? -1 : c;

Slightly shorter and somewhat fewer exception cases than the other proposals here, edited to show how to handle -1 case. Note that the predicate is the inverse of the predicate in the question because we want to count how many characters ARE digits before we find a non-digit.

like image 184
Ian Mercer Avatar answered Oct 20 '22 00:10

Ian Mercer


You're not missing anything. There is no IndexOf in the manner you're searching for in the framework. The closest thing you could do without rolling your own would be

text
  .Select((c, index) => new { Char = c, Index = index })
  .Where(pair => !Char.IsDigit(pair.Char))
  .Select(pair => pair.Index)
  .FirstOrDefault(-1);

However that is not easy to follow and causes senseless allocations. I'd much prefer to roll my own IndexOf in this case.

EDIT Whoops. Forgot that FirstOrDefault is a function I have hand rolled in my apps and is not a part of the standard LINQ libraries with this overload.

public static T FirstOrDefault<T>(this IEnumerable<T> enumerable, T defaultValue) {
  using (var enumerator = enmumerable.GetEnumerator()) {
    if (enumerator.MoveNext()) {
      return enumerator.Current;
    }
    return defaultValue;
}

Here is a version that works without any custom extensions. Note this is for example only, please don't put this in your app ;)

text
  .Select((c, index) => new { Char = c, Index = index })
  .Where(pair => !Char.IsDigit(pair.Char))
  .Select(pair => pair.Index)
  .Concat(Enumerable.Repeat(-1, 1))
  .First();
like image 35
JaredPar Avatar answered Oct 20 '22 01:10

JaredPar