2009-09-22 35 views
18

Tôi đang tìm một hàm thư viện Erlang sẽ trả về chỉ mục của một phần tử cụ thể trong danh sách.Danh sách Erlang: chức năng index_of?

Vì vậy, nếu

X=[10,30,50,70] 

sau đó

lists:index_of(30, X) 

sẽ trở về 1, vv, giống như indexOf() phương pháp java.util.List 's.

Phương pháp này có tồn tại trong lib chuẩn Erlang không? Tôi đã thử tìm kiếm trong mô-đun danh sách nhưng không may mắn. Hay tôi nên tự viết nó?

Cảm ơn.

+5

Nếu bạn định truy cập các mục theo chỉ mục thì tốt hơn là xem mô-đun mảng. – Christian

Trả lời

21

Bạn sẽ phải xác định đó cho mình, như thế này:

index_of(Item, List) -> index_of(Item, List, 1). 

index_of(_, [], _) -> not_found; 
index_of(Item, [Item|_], Index) -> Index; 
index_of(Item, [_|Tl], Index) -> index_of(Item, Tl, Index+1). 

Lưu ý tuy nhiên đó accesing yếu tố thứ N của một danh sách là O (N), vì vậy một thuật toán thường truy cập một danh sách bằng chỉ số sẽ kém hiệu quả hơn cái lặp lại theo tuần tự.

+4

Sẽ giống Erlang hơn để trả về một nguyên tử như 'not_found' thay vì' -1'. Bằng cách này, nếu bạn quên thử nghiệm cho trường hợp này, bạn sẽ nhận được một lỗi nhanh chóng. –

+0

Điểm tốt. Đã thay đổi. – sepp2k

+1

Việc lập chỉ mục có thể bắt đầu từ 1 thay vì 0. – Zed

1

Chức năng này rất không phổ biến đối với Erlang và đây có thể là lý do tại sao nó không nằm trong thư viện chuẩn. Không ai có kinh nghiệm lập trình Erlang cần nó và không khuyến khích sử dụng các thuật toán bằng cách sử dụng chức năng này. Khi ai đó cần nó, có thể viết cho mục đích riêng nhưng những dịp rất hiếm này không phải là lý do để đưa nó vào stdlib. Thiết kế cấu trúc dữ liệu của bạn theo cách thích hợp thay vì yêu cầu chức năng này. Trong hầu hết các trường hợp, hàm này chỉ ra lỗi trong thiết kế.

+1

Vậy ý kiến ​​của bạn là gì - với tư cách là một lập trình viên Erlang có kinh nghiệm, tôi cho rằng - về danh sách: thứ n và danh sách: các hàm nthtail? – Zed

+1

Đó chỉ là một tuyên bố vô lý. Bạn hoàn toàn không có ý tưởng những gì tôi cần chức năng này cho. – Justin

+0

"Không ai có kinh nghiệm lập trình Erlang cần nó" Đoán "các lập trình viên Erlang có kinh nghiệm" của bạn không có xu hướng đối phó với các vấn đề thế giới thực? – Justin

2

giải pháp khác (nhận xét rằng đây là những cơ sở-index = 1):

index_of(Value, List) -> 
    Map = lists:zip(List, lists:seq(1, length(List))), 
    case lists:keyfind(Value, 1, Map) of 
     {Value, Index} -> Index; 
     false -> notfound 
    end. 

index_of(Value, List) -> 
    Map = lists:zip(List, lists:seq(1, length(List))), 
    case dict:find(Value, dict:from_list(Map)) of 
     {ok, Index} -> Index; 
     error -> notfound 
    end. 

Tại một số điểm, khi danh sách bạn vượt qua để các chức năng này có đủ dài, chi phí xây dựng Danh mục bổ sung hoặc dict trở nên quá đắt. Nếu bạn có thể tránh thực hiện việc xây dựng mỗi khi bạn muốn tìm kiếm danh sách bằng cách giữ danh sách ở định dạng đó bên ngoài các chức năng này, bạn sẽ loại bỏ phần lớn chi phí.

Sử dụng từ điển sẽ băm các giá trị trong danh sách và giúp giảm thời gian tra cứu chỉ mục thành O (log N), vì vậy tốt hơn nên sử dụng nó cho các danh sách lớn, đơn lẻ.

Nói chung, tùy bạn, người lập trình, tổ chức dữ liệu của bạn thành các cấu trúc phù hợp với cách bạn sẽ sử dụng chúng. Tôi đoán là sự vắng mặt của index_of được xây dựng sẵn là để khuyến khích xem xét như vậy. Nếu bạn đang thực hiện tra cứu một khóa - đó thực sự là những gì index_of() là - sử dụng một từ điển. Nếu bạn đang thực hiện tra cứu đa khóa, hãy sử dụng danh sách các bộ dữ liệu có danh sách: keyfind() et al. Nếu danh sách của bạn quá lớn, một giải pháp ít đơn giản hơn có lẽ là tốt nhất.

14

Như những người khác đã lưu ý, có nhiều cách hiệu quả hơn để giải quyết vấn đề này. Nhưng nếu bạn đang tìm kiếm cái gì nhanh chóng, điều này đã làm việc cho tôi:

string:str(List, [Element]). 
-1

dễ dàng hơn nhiều cách:

index_of(Elem, List) -> 
    {Map, _} = lists:mapfoldr(fun(X, I) -> {{X, I}, I + 1} end, 0, List), 
    {_, Index} = lists:keyfind(Elem, 1, Map), Index. 
+1

Điều này dường như chỉ số theo thứ tự ngược lại: 'index_of (foo, [foo, bar, baz]).' Có giá trị là 2. –

-1

Tôi nghĩ rằng nhà văn làm cho một trường hợp hợp lệ. Đây là trường hợp sử dụng của tôi từ một ứng dụng ghi nhật ký. Mục tiêu là để kiểm tra mức độ nghiêm trọng của một lỗi chống lại các hành động được thực hiện đối với các mức độ phản ứng lỗi khác nhau.

get_index(A,L) -> 
    get_index(A,L,1). 
get_index(A,[A|_],N) -> 
    N; 
get_index(A,[_|T],N) -> 
    get_index(A,T,N+1). 

get_severity(A) -> 
    Severity=[debug,info,warn,error], 
    get_index(A,Severity). 
+0

Tôi vừa viết một phương thức rất giống với phương thức này; Tôi đã kết thúc bằng cách sử dụng một cái gì đó như get_severity (debug) -> 1; get_severity (thông tin) -> 2; v.v. - nên nhanh hơn một chút, và dialyzer sẽ thông báo nếu tôi truyền nó không hợp lệ – Seb

-1

Hàm sau trả về danh sách chỉ mục của phần tử đã cho trong danh sách. Kết quả có thể được sử dụng để lấy chỉ mục của lần xuất hiện đầu tiên hoặc cuối cùng của phần tử trùng lặp trong danh sách.

indices_of(Element, L) ->                                       
    Indices = lists:zip(lists:seq(1,length(L)), L),                                 
    [ I || {I, E} <- Indices, E == Element ]. 
Các vấn đề liên quan