2015-01-30 11 views
7

Jestem nowym użytkownikiem Elixir i nadal bardzo się myli z dopasowywaniem wzorca.Filtrowanie/dopasowywanie wzorca w zagnieżdżonej strukturze danych

[%{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 

, że najlepszym sposobem, aby znaleźć kraj za pomocą kodu?

Odpowiedz

9

Można wzór mecz tak głęboko, jak chcesz:

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) 

Można również użyć Enum.find/3 z match?/2, które mogą być bardziej czytelne (jak sugeruje się w innej odpowiedzi).

+0

To jest świetna odpowiedź, nie wiedziałem nawet, że druga forma była możliwa! – greggreg

+0

Świetna odpowiedź, jeden mały dodatek, który pozbędzie się ostrzeżenia. Zmienna 't' w drugiej klauzuli function nie jest używana i dlatego powinna być określona jako' _t'. – b73

+0

@ b73 dobry połów! Napisałem to na telefon komórkowy, więc nawet go nie uruchomiłem, oops :) Dzięki! – whatyouhide

7

Można zrobić to w ten sposób:

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

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

Makro 'match?/2' jest ** ładne **! Nie wiem, jak nie wiedziałem o tym. Dzięki, Patrick! – whatyouhide

+1

Tak, byłem naprawdę podekscytowany, kiedy się o tym dowiedziałem! Najpierw [napisał makro] (https://gist.github.com/padde/a759b18bca7851e8ffaa), aby to zrobić. Niemniej jednak to było moje pierwsze makro i wiele się nauczyłem ;-) –

2

Elixir nie mają wbudowane wzór pasujący do starają się odfiltrować pewne elementy listy w oparciu o ich wartości.

można napisać mecz wzór sprawdzić poszczególne elementy tak:

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

a następnie przekazać, że do Enum.find:

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

Albo uogólniać możesz:

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

Zmiana znalezionego filtra i wyświetlenie listy wyników:

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"}]