Bagaimana cara mendapatkan indeks suatu item dalam daftar dalam satu langkah?

193

Bagaimana saya bisa menemukan indeks suatu item dalam daftar tanpa mengulanginya?

Saat ini ini tidak terlihat sangat bagus - mencari daftar item yang sama dua kali, hanya untuk mendapatkan indeks:

var oProp = something;

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

Jawaban:

434

Bagaimana dengan Metode List.FindIndex :

int index = myList.FindIndex(a => a.Prop == oProp);

Metode ini melakukan pencarian linier; oleh karena itu, metode ini adalah operasi O (n), di mana n adalah Hitung.

Jika item tidak ditemukan, itu akan mengembalikan -1

Alex Filipovici
sumber
2
Bagaimana dengan int index?
Dylan Czenski
2
@DylanChensky dia terlalu banyak mengkode JS
lennyy
9
Untuk referensi, jika barang tersebut tidak ditemukan; itu akan mengembalikan -1
Daniel Filipe
102

Untuk tipe sederhana, Anda dapat menggunakan "IndexOf":

List<string> arr = new List<string>();
arr.Add("aaa");
arr.Add("bbb");
arr.Add("ccc");
int i = arr.IndexOf("bbb"); // RETURNS 1.
Jose Manuel Abarca Rodríguez
sumber
71

EDIT: Jika Anda hanya menggunakan List<>dan Anda hanya perlu indeks, maka List.FindIndexmemang pendekatan yang terbaik. Saya akan meninggalkan jawaban ini di sini untuk mereka yang membutuhkan sesuatu yang berbeda (misalnya di atas apa pun IEnumerable<>).

Gunakan kelebihan Selectyang mengambil indeks dalam predikat, sehingga Anda mengubah daftar Anda menjadi pasangan (indeks, nilai):

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

Kemudian:

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

Atau jika Anda hanya menginginkan indeks dan Anda menggunakannya di banyak tempat, Anda dapat dengan mudah menulis metode ekstensi Anda sendiri yang seperti itu Where, tetapi alih-alih mengembalikan item asli, itu mengembalikan indeks item-item yang cocok dengan predikat.

Jon Skeet
sumber
Sepertinya yang dia inginkan hanyalah indeks. Daftar <>. FindIndex (Predikat <>) adalah pendekatan terbaik. Meskipun judul pertanyaan akan menyindir sebaliknya, deskripsi OP cukup jelas, ia hanya membutuhkan indeks "int theThingIActuallyAmInterestedIn"
Louis Ricci
1
@LastCoder: Aha - telah melewatkan FindIndex. Ya, saya sepenuhnya setuju.
Jon Skeet
Untuk lebih jelasnya, apakah "index / value -> single" approach "lebih baik" (di sini berarti lebih cepat dalam hal Big-O) daripada secara manual mengulangi dua kali? Atau apakah penyedia LINQ2Objects cukup pintar untuk mengoptimalkan salah satu iterasi? (Saya membuat asumsi bahwa baik Select maupun Single secara umum adalah operasi O (n))
sara
1
@ Kai: Saya pikir Anda perlu membaca tentang cara kerja LINQ, pada dasarnya. Terlalu rumit untuk dijelaskan secara terperinci dalam komentar. Namun ... ini hanya mengulangi pengumpulan sumber sekali saja. LINQ membuat jalur pipa, yang dengan malas mengubah urutan input menjadi urutan lain, dan kemudian Single()operasi beralih pada urutan itu dan menemukan item tunggal yang cocok dengan predikat. Untuk lebih jelasnya, baca seri blog edulinq saya: codeblog.jonskeet.uk/category/edulinq
Jon Skeet
1
+1 Saya membutuhkan solusi ini. Bos pikir aku pintar sekali. Saya disarankan untuk secara hati-hati mendokumentasikan ini, karena menggunakan jenis anonim dan mungkin tidak jelas ke pembuat kode berikutnya di area tersebut.
Adam Wells
14

Jika Anda tidak ingin menggunakan LINQ, maka:

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

dengan cara ini Anda hanya mengulang daftar sekali saja.

gzaxx
sumber
22
@ Raja tidak ada yang mengatakan itu.
Tomer W
1
Apakah ini implementasi yang sama dengan Linq FindIndexkarena minat?
Coops
2
mungkin bukan kode yang sama, Daftar memiliki beberapa optimasi yang rapi di sana-sini. tetapi saya merasa sulit untuk percaya bahwa mereka dapat mencari daftar yang tidak berurutan dalam waktu kurang dari O (n), jadi saya akan mengatakan mereka mungkin sangat mirip dalam praktiknya.
sara
6
  1. Solusi sederhana untuk menemukan indeks untuk nilai string apa pun dalam Daftar.

Berikut ini adalah kode untuk Daftar String:

int indexOfValue = myList.FindIndex(a => a.Contains("insert value from list"));
  1. Solusi sederhana untuk menemukan indeks untuk setiap nilai Integer dalam Daftar.

Berikut adalah Kode untuk Daftar Integer:

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

sumber
2

Berikut adalah metode ekstensi yang dapat disalin / ditempel untuk IEnumerable

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;
    }
}

Nikmati.

Snæbjørn
sumber
2

Jika ada yang bertanya-tanya tentang Arrayversi, itu seperti ini:

int i = Array.FindIndex(yourArray, x => x == itemYouWant);
Ali Bordbar
sumber