Làm thế nào để có được chỉ mục của một mục trong danh sách trong một bước duy nhất?


193

Làm thế nào tôi có thể tìm thấy chỉ mục của một mục trong danh sách mà không lặp qua nó?

Hiện tại điều này trông không đẹp lắm - tìm kiếm trong danh sách cho cùng một mục hai lần, chỉ để lấy chỉ mục:

var oProp = something;

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

Câu trả lời:


434

Làm thế nào về Phương thức List.Find Index :

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

Phương pháp này thực hiện tìm kiếm tuyến tính; do đó, phương thức này là một hoạt động O (n), trong đó n là Count.

Nếu không tìm thấy vật phẩm, nó sẽ trả về -1


2
Thế còn int index?
Dylan Cundredki

2
@DylanChensky anh ấy đã mã hóa JS quá nhiều
lennyy

9
Để tham khảo, nếu không tìm thấy mục; nó sẽ trở lại -1
Daniel Filipe

102

Đối với các loại đơn giản, bạn có thể sử dụng "IndexOf":

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

71

EDIT: Nếu bạn chỉ sử dụng một List<>và bạn chỉ cần chỉ mục, thì đó List.FindIndexthực sự là cách tiếp cận tốt nhất. Tôi sẽ để câu trả lời này ở đây cho những người cần bất cứ điều gì khác biệt (ví dụ như trên bất kỳ IEnumerable<>).

Sử dụng quá tải trong Selectđó có một chỉ mục trong vị ngữ, do đó bạn chuyển đổi danh sách của mình thành một cặp (chỉ mục, giá trị):

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

Sau đó:

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

Hoặc nếu bạn chỉ muốn chỉ mục và bạn đang sử dụng điều này ở nhiều nơi, bạn có thể dễ dàng viết phương thức tiện ích mở rộng của riêng mình Where, nhưng thay vì trả về các mục ban đầu, nó sẽ trả về các chỉ mục của các mục phù hợp với vị từ.


Có vẻ như tất cả những gì anh ấy muốn là chỉ số. Danh sách <>. Find Index (Dự đoán <>) là cách tiếp cận tốt nhất. Mặc dù tiêu đề câu hỏi sẽ ẩn ý khác, nhưng mô tả của OP khá rõ ràng, anh ta chỉ cần chỉ mục "int theT BreathIActualAmInterestedIn"
Louis Ricci

1
@LastCoder: Aha - đã bỏ lỡ Find Index. Vâng, tôi hoàn toàn đồng ý.
Jon Skeet

Nói rõ hơn, cách tiếp cận "chỉ số / giá trị -> đơn" "tốt hơn" (ở đây có nghĩa là nhanh hơn về mặt Big-O) so với lặp lại thủ công hai lần? Hoặc là nhà cung cấp LINQ2Objects đủ thông minh để tối ưu hóa một trong các lần lặp lại? (Tôi đang đưa ra giả định rằng cả Chọn và Đơn nói chung là các thao tác O (n))
sara

1
@kai: Về cơ bản, tôi nghĩ bạn cần đọc về cách thức hoạt động của LINQ. Quá phức tạp để giải thích chi tiết trong một bình luận. Tuy nhiên ... đây chỉ là lần lặp lại trên bộ sưu tập nguồn một lần. LINQ thiết lập một đường ống dẫn, biến đổi một cách lười biếng chuỗi đầu vào thành một chuỗi khác, và sau đó Single()thao tác lặp lại chuỗi đó và tìm thấy một mục duy nhất khớp với vị ngữ. Để biết thêm chi tiết, hãy đọc loạt blog edulinq của tôi: codeblog.jonskeet.uk/c Ab / edulinq
Jon Skeet

1
+1 Tôi cần giải pháp này. Ông chủ nghĩ tôi thông minh một lần. Tôi được khuyên nên ghi chép cẩn thận điều này, vì nó đã sử dụng một loại ẩn danh và có thể không rõ ràng đối với người viết mã tiếp theo trong khu vực.
Adam Wells

14

Nếu bạn không muốn sử dụng LINQ, thì:

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

Bằng cách này, bạn chỉ lặp lại danh sách một lần.


22
@KingKing noone nói là có.
Tomer W

1
Đây có phải là thực hiện tương tự như Linq FindIndexkhông quan tâm?
Coops

2
có lẽ không cùng mã, Danh sách có một số tối ưu hóa gọn gàng ở đây và đó. nhưng tôi cảm thấy khó tin rằng họ có thể tìm kiếm một danh sách không có thứ tự trong ít hơn O (n), vì vậy tôi có thể nói rằng họ có thể thực sự giống nhau trong thực tế.
sara

6
  1. Giải pháp đơn giản để tìm chỉ mục cho bất kỳ giá trị chuỗi nào trong Danh sách.

Đây là mã cho List Of String:

int indexOfValue = myList.FindIndex(a => a.Contains("insert value from list"));
  1. Giải pháp đơn giản để tìm chỉ mục cho bất kỳ giá trị Số nguyên nào trong Danh sách.

Đây là Mã cho Danh sách Số nguyên:

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

2

Đây là một phương thức mở rộng có thể sao chép / dán cho 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;
    }
}

Thưởng thức.


2

Nếu bất cứ ai tự hỏi về Arrayphiên bản, nó sẽ như thế này:

int i = Array.FindIndex(yourArray, x => x == itemYouWant);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.