21

Is there a way to find the index from list of partial prefixes with Linq, something like:

List<string> PartialValues = getContentsOfPartialList();
string wholeValue  = "-moz-linear-gradient(top,  #1e5799 0%, #7db9e8 100%)";
int indexOfPartial = PartialValues
                      .IndexOf(partialPrefix=>wholeValue.StartsWith(partialPrefix));

Unfortunately, IndexOf() doesn't accept lambda expression. Is there a similar Linq method for this?

Annie
  • 3,090
  • 9
  • 36
  • 74

5 Answers5

44

You don't need LINQ at all, List<T> has a method FindIndex.

int indexOfPartial = PartialValues
    .FindIndex(partialPrefix => wholeValue.StartsWith(partialPrefix));

For the sake of completeness, you can use LINQ, but it's not necessary:

int indexOfPartial = PartialValues
  .Select((partialPrefix , index) => (partialPrefix , index))
  .Where(x => wholeValue.StartsWith(x.partialPrefix))
  .Select(x => x.index)
  .DefaultIfEmpty(-1)
  .First();
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • The Linq code doesn't seem to be correct. You need to call `.First()` to convert sequence into value. Note that trying to use `.FirstOrDefault()` instead to avoid exception handling will make value of index ambiguous: it will hold 0 for both cases when item not found and item was found at the head of list. – firegurafiku Nov 13 '14 at 02:32
  • 1
    @firegurafiku: i've only just noticed your comment. Fixed. Now it has the same behaviour as `List.FindIndex`. A good example that LINQ is not always more readable/concise. – Tim Schmelter Apr 07 '15 at 21:44
6

Tim has the most correct answer (https://stackoverflow.com/a/19792531/467172), though if you actually wanted an extension method for IEnumerable<T> then you could do it with something like this:

public static int IndexOf<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    int index = 0;
    foreach (var item in source)
    {
        if (predicate(item)) return index;
        index++;
    }

    return -1;
}
Community
  • 1
  • 1
Anthony
  • 9,451
  • 9
  • 45
  • 72
4

If you have List<T>, see accepted answer.

In case you have IEnumerable (or other collection that implements it) instead of List, you can use following LINQ code:

int index = PartialValues.TakeWhile(partialPrefix=> ! wholeValue.StartsWith(partialPrefix)).Count();

Pay attention at the negation operator (!) in lambda expression: lambda expression should return true for elements that do NOT match your condition.

Code will return number of elements (e.g. index will point at position immediately after the last element) if no elements match the condition.

Community
  • 1
  • 1
nevermind
  • 2,300
  • 1
  • 20
  • 36
0

One thing I've done, which also works with simple arrays, is to start by iterating over indices instead of over the content. Shown here with a case insensitive lookup:

string[] names = { "Joe", "Bill", "Mary" };

int index = Enumerable.Range(0, names.Length).Where(
        i => String.Equals(names[i], "bill", StringComparison.InvariantCultureIgnoreCase))
        .DefaultIfEmpty(-1).First();
Nyerguds
  • 5,360
  • 1
  • 31
  • 63
-1

You can use Enumerable.First

string partialStr = PartialValues.FirstOrDefault(partialPrefix=>wholeValue.StartsWith(partialPrefix);
int partialIndex = PartialValues.IndexOf(partialStr);
Jacob
  • 995
  • 4
  • 12