2012-02-15 17 views
10

Mam aplikację internetową C# .Net MVC3. Mam poniższą tablicę znaków.LINQ indexOf określonego wpisu

public static string[] HeaderNamesWbs = new[] 
             { 
              WBS_NUMBER, 
              BOE_TITLE, 
              SOW_DESCRIPTION, 
              HARRIS_WIN_THEME, 
              COST_BOGEY 
             }; 

Chcę znaleźć indeks danego wpisu w innej pętli. Myślałem, że lista będzie miała IndexOf. Nie mogę tego znaleźć. Jakieś pomysły?

+0

LINQ działa na zbiorach, które nie mają operatora indeksu. Nie ma "IndexOf" – cadrell0

+1

@ cadrell0: Można go jednak łatwo zbudować - zobacz moją odpowiedź. Istnieją różne operatory LINQ, które zapewniają indeks. –

Odpowiedz

35

Cóż można użyć Array.IndexOf:

int index = Array.IndexOf(HeaderNamesWbs, someValue); 

Albo po prostu zadeklarować HeaderNamesWbs jako IList<string> zamiast - które nadal może być tablicą jeśli chcesz:

public static IList<string> HeaderNamesWbs = new[] { ... }; 

Zauważ, że będę zniechęcać od odsłaniając tablicę jako public static nawet public static readonly. Należy rozważyć ReadOnlyCollection:

public static readonly ReadOnlyCollection<string> HeaderNamesWbs = 
    new List<string> { ... }.AsReadOnly(); 

Jeśli kiedykolwiek chcesz to dla IEnumerable<T>, można użyć:

var indexOf = collection.Select((value, index) => new { value, index }) 
         .Where(pair => pair.value == targetValue) 
         .Select(pair => pair.index + 1) 
         .FirstOrDefault() - 1; 

(The +1 i -1 są tak, że powróci -1 dla "missing" zamiast 0.)

+0

@Jon ... dzięki! Dobry towar. Podoba mi się pomysł ReadOnlyCollection ... doceniam to: – MikeTWebb

+0

@ jon-skeet Czy nie ma większego sensu tworzenie domyślnego '-1'? 'collection.Wybierz ((value, index) => new {value, index}) Gdzie (pair => pair.value == targetValue). Wybierz (pair => pair.index) .FirstOrDefault (-1);' –

+0

@lund.mikkel: Nie ma przeciążenia 'FirstOrDefault', które przyjmuje domyślną wartość do dostarczenia (w przeciwieństwie do' DefaultIfEmpty' na przykład). –

4

Prawy List ma IndexOf(), po prostu zadeklarować ją jako ILIst<string> zamiast string[]

public static IList<string> HeaderNamesWbs = new List<string> 
            { 
             WBS_NUMBER, 
             BOE_TITLE, 
             SOW_DESCRIPTION, 
             HARRIS_WIN_THEME, 
             COST_BOGEY 
            }; 

int index = HeaderNamesWbs.IndexOf(WBS_NUMBER); 

MSDN: List(Of T).IndexOf Method (T)

8

Jestem spóźniony do wątku tutaj. Ale chciałem podzielić się z tym moim rozwiązaniem. Jon's jest niesamowity, ale ja wolę proste lambdy na wszystko.

Możesz rozszerzyć LINQ, aby uzyskać to, co chcesz. To dość proste do zrobienia. Pozwoli to na użycie składni jak:

// Gets the index of the customer with the Id of 16. 
var index = Customers.IndexOf(cust => cust.Id == 16); 

Jest to prawdopodobnie nie jest częścią LINQ domyślnie, ponieważ wymaga wyliczenia. To nie jest kolejny odroczony selektor/orzecznik.

Należy również pamiętać, że zwraca tylko pierwszy indeks. Jeśli chcesz indeksów (liczba mnoga), powinieneś zwrócić IEnumerable<int> i yeild return index wewnątrz metody. I oczywiście nie zwracaj -1. Byłoby użyteczne tam, gdzie nie filtrujesz według klucza podstawowego.

public static int IndexOf<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { 

    var index = 0; 
    foreach (var item in source) { 
     if (predicate.Invoke(item)) { 
      return index; 
     } 
     index++; 
    } 

    return -1; 
    }