วิธีรับดัชนีของรายการในรายการในขั้นตอนเดียว?


193

ฉันจะค้นหาดัชนีของรายการในรายการโดยไม่วนซ้ำได้อย่างไร

ขณะนี้สิ่งนี้ดูไม่ดีนัก - ค้นหารายการเดียวกันสองครั้งเพื่อรับดัชนี:

var oProp = something;

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

คำตอบ:


435

วิธีการเกี่ยวกับวิธี List.FindIndex :

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

วิธีนี้ทำการค้นหาเชิงเส้น ดังนั้นวิธีนี้เป็นการดำเนินการ O (n) โดยที่ n คือ Count

หากไม่พบรายการมันจะส่งคืน -1


2
แล้วไงint indexล่ะ
Dylan Czenski

2
@DylanChensky เขาเข้ารหัส JS มากเกินไป
lennyy

9
สำหรับการอ้างอิงหากไม่พบรายการ; มันจะกลับมา -1
Daniel Filipe


71

แก้ไข: หากคุณใช้เพียงList<>และคุณต้องการเพียงดัชนีก็List.FindIndexเป็นวิธีที่ดีที่สุด ฉันจะปล่อยคำตอบนี้ไว้ที่นี่สำหรับผู้ที่ต้องการอะไรที่ต่างออกไป (เช่นที่ด้านบนIEnumerable<>)

ใช้โอเวอร์โหลดSelectซึ่งใช้ดัชนีในเพรดิเคตดังนั้นคุณแปลงรายการของคุณให้เป็นคู่ (ดัชนีค่า)

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

แล้ว:

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

หรือถ้าคุณต้องการแค่ดัชนีและคุณใช้สิ่งนี้ในหลาย ๆ ที่คุณสามารถเขียนวิธีการขยายของคุณเองได้อย่างง่ายดายWhereแต่แทนที่จะส่งคืนรายการต้นฉบับมันจะส่งคืนดัชนีของรายการเหล่านั้นที่ตรงกับภาคแสดง


ดูเหมือนว่าทั้งหมดที่เขาต้องการคือดัชนี List <>. FindIndex (Predicate <>) เป็นวิธีที่ดีที่สุด แม้ว่าชื่อคำถามจะไม่ชัดเจนมิฉะนั้นคำอธิบายของ OP ค่อนข้างชัดเจนว่าเขาต้องการเพียงดัชนี "int theThingIA จริง ๆ แล้วผู้ที่สนใจ"
Louis Ricci

1
@LastCoder: Aha - พลาด FindIndex ใช่ฉันเห็นด้วยอย่างยิ่ง
Jon Skeet

เพื่อความชัดเจน "ดัชนี / ค่า -> วิธีการ" เดียว "ดีกว่า" (นี่หมายถึงความรวดเร็วในแง่ของ Big-O) มากกว่าการทำซ้ำสองครั้งด้วยตนเองหรือไม่ หรือผู้ให้บริการ LINQ2Objects ฉลาดพอที่จะปรับการทำงานอย่างใดอย่างหนึ่งออกไปได้หรือไม่ (ฉันทำสมมติฐานที่ว่าทั้งสองเลือกและเตียงเดี่ยวทั่วไปพูดเป็น O (n) การดำเนินงาน)
ซาร่า

1
@ ไก่: ฉันคิดว่าคุณจำเป็นต้องอ่านวิธีการทำงานของ LINQ โดยทั่วไป มันซับซ้อนเกินไปที่จะอธิบายรายละเอียดในความคิดเห็น อย่างไรก็ตาม ... นี่เป็นเพียงการวนซ้ำในคอลเลกชันแหล่งข้อมูลหนึ่งครั้ง LINQ ตั้งค่าไพพ์ไลน์ซึ่งแปลงลำดับอินพุตเป็นอีกลำดับอย่างเกียจคร้านจากนั้นการSingle()ดำเนินการจะวนซ้ำไปตามลำดับนั้นและค้นหารายการเดียวที่ตรงกับเพรดิเคต สำหรับรายละเอียดเพิ่มเติมอ่านชุดบล็อก edulinq ของฉัน: codeblog.jonskeet.uk/category/edulinq
Jon Skeet

1
+1 ฉันต้องการโซลูชันนี้ บอสคิดว่าฉันฉลาดทีเดียว ฉันได้รับคำแนะนำให้ทำเอกสารนี้อย่างระมัดระวังเนื่องจากมันใช้ประเภทที่ไม่ระบุชื่อและอาจไม่ชัดเจนกับ coder ถัดไปในพื้นที่
Adam Wells

14

หากคุณไม่ต้องการใช้ LINQ ให้ทำดังนี้

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

วิธีนี้คุณกำลังทำซ้ำรายการเพียงครั้งเดียว


22
@KingKing ไม่มีใครบอกว่ามันเป็น
Tomer W

1
นี่เป็นการใช้งานแบบเดียวกับ Linq FindIndexหรือไม่?
Coops

2
อาจไม่ใช่รหัสเดียวกัน List มีการปรับแต่งที่เหมาะสมที่นี่และที่นั่น แต่ฉันคิดว่ามันยากที่จะเชื่อว่าพวกเขาสามารถค้นหารายชื่อที่ไม่มีการเรียงลำดับในน้อยกว่า O (n) ดังนั้นฉันคิดว่ามันอาจคล้ายกันในทางปฏิบัติ
ร่า

6
  1. วิธีง่ายๆในการค้นหาดัชนีสำหรับค่าสตริงใด ๆ ในรายการ

นี่คือรหัสสำหรับรายการของสตริง:

int indexOfValue = myList.FindIndex(a => a.Contains("insert value from list"));
  1. วิธีง่ายๆในการค้นหาดัชนีสำหรับค่าจำนวนเต็มใด ๆ ในรายการ

นี่คือรหัสสำหรับรายการของจำนวนเต็ม:

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

2

ต่อไปนี้เป็นวิธีส่วนขยายสำหรับคัดลอก / วางสำหรับ 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;
    }
}

สนุก.


2

หากใครสงสัยในArrayเวอร์ชั่นมันจะเป็นดังนี้:

int i = Array.FindIndex(yourArray, x => x == itemYouWant);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.