Listedeki bir öğenin dizinini tek bir adımda nasıl alabilirim?


193

Listedeki bir öğenin dizinini, döngü içinde olmadan nasıl bulabilirim?

Şu anda bu çok hoş görünmüyor - aynı öğeyi listede iki kez aramak, sadece dizini almak için:

var oProp = something;

int theThingIActuallyAmInterestedIn = myList.IndexOf(myList.Single(i => i.Prop == oProp));

Yanıtlar:



103

Basit tipler için "IndexOf" kullanabilirsiniz:

List<string> arr = new List<string>();
arr.Add("aaa");
arr.Add("bbb");
arr.Add("ccc");
int i = arr.IndexOf("bbb"); // RETURNS 1.

71

DÜZENLEME: Yalnızca a kullanıyorsanız List<>ve yalnızca dizine ihtiyacınız varsa , o List.FindIndexzaman gerçekten en iyi yaklaşımdır. Bu cevabı farklı bir şeye ihtiyaç duyanlar için burada bırakacağım (örneğin herhangi birinin üstünde IEnumerable<>).

SelectYüklemede bir dizini alan aşırı yükü kullanın , böylece listenizi bir (dizin, değer) çiftine dönüştürürsünüz:

var pair = myList.Select((Value, Index) => new { Value, Index })
                 .Single(p => p.Value.Prop == oProp);

Sonra:

Console.WriteLine("Index:{0}; Value: {1}", pair.Index, pair.Value);

Veya yalnızca dizini istiyorsanız ve bunu birden çok yerde kullanıyorsanız, kendi uzantı yönteminizi kolayca yazabilirsiniz Where, ancak orijinal öğeleri iade etmek yerine, yüklemle eşleşen bu öğelerin dizinlerini döndürdü.


Tüm istediği dizin. Liste <>. FindIndex (Tahmin <>) en iyi yaklaşımdır. Her ne kadar soru başlığı başka türlü ima edecek olsa da, OP'nin açıklaması sadece "intThingIActuallyAmInterestedIn" endeksine ihtiyacı olduğu açıktır
Louis Ricci

1
@LastCoder: Aha - FindIndex'i kaçırmıştı. Evet, tamamen katılıyorum.
Jon Skeet

Açıkça söylemek gerekirse, "indeks / değer -> tek" yaklaşım "(burada Big-O açısından daha hızlı olmak anlamına gelir) iki kez manuel olarak yinelemekten daha mı iyi? Yoksa LINQ2Objects sağlayıcı yinelemelerden birini optimize edecek kadar akıllı mı? (Hem Select hem de Single'ın genel olarak konuşmanın O (n) operasyonları olduğu varsayımını yapıyorum)
sara

1
@kai: Sanırım LINQ'nun nasıl çalıştığını okumalısınız. Bir yorumda ayrıntılı olarak açıklamak çok karmaşık. Ancak ... bu sadece bir kez kaynak koleksiyonu üzerinden yineleniyor. LINQ, giriş dizisini tembel bir şekilde başka bir diziye dönüştüren bir boru hattı kurar ve ardından Single()işlem bu dizi üzerinde tekrarlar ve yüklemle eşleşen tek öğeyi bulur. Daha fazla ayrıntı için edulinq blog dizimi okuyun: codeblog.jonskeet.uk/category/edulinq
Jon Skeet

1
+1 Bu çözüme ihtiyacım vardı. Patron bir kereliğine akıllı olduğumu düşünüyordu. Anonim bir tür kullandığından ve bölgedeki bir sonraki kodlayıcıya açık olmayabileceğinden, bunu dikkatlice belgelemem tavsiye edildi.
Adam Wells

14

LINQ kullanmak istemiyorsanız, o zaman:

int index;
for (int i = 0; i < myList.Count; i++)
{
    if (myList[i].Prop == oProp)
    {
       index = i;
       break;
    }
}

bu şekilde listeyi yalnızca bir kez yinelersiniz.


22
@KingKing kimse bunu söylemedi.
Tomer W

1
Bu, Linq ile aynı uygulama FindIndexmı?
Coops

2
muhtemelen aynı kod değil, List burada ve orada bazı temiz optimizasyonlar vardır. ancak sırasız bir listeyi O (n) 'den daha az bir sürede arayabileceklerine inanmakta zorlanıyorum, bu yüzden pratikte muhtemelen benzer olduklarını söyleyebilirim.
sara

6
  1. Listedeki herhangi bir dize değeri için dizin bulmak için basit bir çözüm.

İşte Dize Listesi için kod:

int indexOfValue = myList.FindIndex(a => a.Contains("insert value from list"));
  1. Listedeki herhangi bir Tamsayı değeri için dizin bulmak için basit bir çözüm.

İşte Tamsayı Listesi Kodu:

    int indexOfNumber = myList.IndexOf(/*insert number from list*/);

2

İşte IEnumerable için kopyala / yapıştır özellikli uzantı yöntemi

public static class EnumerableExtensions
{
    /// <summary>
    /// Searches for an element that matches the conditions defined by the specified predicate,
    /// and returns the zero-based index of the first occurrence within the entire <see cref="IEnumerable{T}"/>.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="predicate">The predicate.</param>
    /// <returns>
    /// The zero-based index of the first occurrence of an element that matches the conditions defined by <paramref name="predicate"/>, if found; otherwise it'll throw.
    /// </returns>
    public static int FindIndex<T>(this IEnumerable<T> list, Func<T, bool> predicate)
    {
        var idx = list.Select((value, index) => new {value, index}).Where(x => predicate(x.value)).Select(x => x.index).First();
        return idx;
    }
}

Zevk almak.


2

Birisi Arraysürüm için merak ederse , şu şekilde gider:

int i = Array.FindIndex(yourArray, x => x == itemYouWant);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.