2015-01-30 71 views
7

Tôi mới sử dụng Elixir và vẫn rất bối rối với mẫu phù hợp.Lọc/Ghép mẫu trong cấu trúc dữ liệu lồng nhau

[%{name: "Deutschland", code: "DE"}, %{name: "Frankreich", code: "FR"}]

def find_by_code([], _name), do: [] 
    def find_by_code([h | t], query) do 
    if h[:code] == query do 
     IO.puts("MATCH") 
     IO.inspect(h) 
    else 
     IO.puts ("No match") 
     find_by_code(t, query) 
    end 
    end 

Đó có phải là cách tốt nhất để tìm nước bằng cách mã?

Trả lời

9

Bạn có thể mô hình phù hợp như sâu như bạn muốn:

def find_by_code([], _query), 
    do: nil # or whatever you want to mean "not found" 

def find_by_code([%{code: query} = country|_t], query), 
    do: IO.inspect(country) 

def find_by_code([_country|t], query), 
    do: find_by_code(t, query) 

Bạn cũng có thể sử dụng Enum.find/3 với match?/2, có thể dễ đọc hơn (như đề xuất trong câu trả lời khác).

+0

Đây là một câu trả lời tuyệt vời, thậm chí không biết biểu mẫu thứ hai là có thể! – greggreg

+0

Câu trả lời hay, một phần bổ sung nhỏ sẽ loại bỏ cảnh báo. Biến 't' trong mệnh đề hàm thứ hai không được sử dụng và do đó nên được chỉ định là' _t'. – b73

+0

@ b73 nắm bắt tốt! Tôi đã viết rằng trên điện thoại di động vì vậy tôi thậm chí không chạy nó, oops :) Cảm ơn! – whatyouhide

7

Bạn có thể làm theo cách này:

countries = [ 
    %{name: "Deutschland", code: "DE"}, 
    %{name: "Frankreich", code: "FR"} 
] 

Enum.find(countries, &match?(%{code: "FR"}, &1)) 
# %{code: "FR", name: "Frankreich"} 
+1

Macro 'match?/2' là ** đẹp **! Tôi không biết làm thế nào tôi không biết về điều đó. Cảm ơn Patrick! – whatyouhide

+1

Vâng, tôi đã thực sự vui mừng khi tôi phát hiện ra về nó, quá! Lần đầu tiên tôi viết [macro] (https://gist.github.com/padde/a759b18bca7851e8ffaa) để làm điều này. Tuy nhiên, nó là vĩ mô đầu tiên của tôi và tôi đã học được rất nhiều trong quá trình ;-) –

2

Elixir không đã xây dựng trong mô hình phù hợp cho cố gắng để lọc ra các mục nhất định của một danh sách dựa trên giá trị của họ.

Bạn có thể viết một mô hình phù hợp để kiểm tra từng mục như sau:

match_country_code = fn (%{:code => "DE"} = country) -> country 
         (_) -> nil 
        end 

Và sau đó vượt qua đó để Enum.find:

lands = [ 
    %{name: "Deutschland", code: "DE"}, 
    %{name: "Frankreich", code: "FR"} 
] 
Enum.find(lands, &(match_country_code.(&1))) 
# => %{code: "DE", name: "Deutschland"} 

Hoặc để khái quát bạn có thể:

lands = [ 
    %{name: "Deutschland", code: "DE"}, 
    %{name: "Frankreich", code: "FR"} 
] 

find_by = fn (list, key, val) -> 
    Enum.find(list, &(Map.get(&1, key)==val)) 
end 

find_by.(lands, :name, "DE") 
#=> %{code: "DE", name: "Deutschland"} 

Thay đổi tìm kiếm thành bộ lọc và nhận danh sách kết quả:

lands = [ 
    %{name: "Deutschland", code: "DE"}, 
    %{name: "Germany", code: "DE"}, 
    %{name: "Frankreich", code: "FR"} 
] 

filter_by = fn (list, key, val) -> 
    Enum.filter(list, &(Map.get(&1, key)==val)) 
end 

filter_by.(lands, :code, "DE") 
#=> [%{code: "DE", name: "Deutschland"}, %{code: "DE", name: "Germany"}] 
Các vấn đề liên quan