2014-12-11 3 views
3

Я построил бинарный поиск в эликсира, но я в конечном итоге с помощью 3, если статьи:Elixir бинарный поиск

if actual == guessed_number, do: 

if actual > guessed_number do: 

if actual < guessed_number do: 

Можно не использовать условными вообще? Может быть, с шаблоном соответствия?

ответ

6

ПРЕДУПРЕЖДЕНИЯ: не использовать это в производстве, это медленнее, чем простой линейный поиск, так как связанные списки не позволяют для произвольного доступа в постоянная время. Это сообщение касается всего лишь аспекта соответствия шаблону.

Теоретически вы можете использовать пункты охраны, но они могут значительно ухудшить ситуацию, если вы переусердствовали. Предполагая, что вы начинаете с реализацией, как это:

defmodule MyEnum do 
    def binsearch(collection, key) do 
    binsearch(collection, key, 1, length(collection)) 
    end 

    defp binsearch(collection, key, lo, hi) do 
    if hi < lo do 
     -1 
    else 
     mid = div(lo + hi, 2) 
     item = Enum.at(collection, mid) 
     cond do 
     key < item -> binsearch(collection, key, lo, mid-1) 
     key > item -> binsearch(collection, key, mid+1, hi) 
     true  -> mid 
     end 
    end 
    end 
end 

Может быть, вы хотите, чтобы извлечь if в пункт охраны:

defmodule MyEnum do 
    def binsearch(collection, key) do 
    binsearch(collection, key, 1, length(collection)) 
    end 

    defp binsearch(_collection, _key, lo, hi) when hi < lo do 
    -1 
    end 

    defp binsearch(collection, key, lo, hi) do 
    mid = div(lo + hi, 2) 
    item = Enum.at(collection, mid) 
    cond do 
     key < item -> binsearch(collection, key, lo, mid-1) 
     key > item -> binsearch(collection, key, mid+1, hi) 
     true  -> mid 
    end 
    end 
end 

Теперь вы также можете вытащить cond из в guard clauses, но это на самом деле не улучшение:

defmodule MyEnum do 
    def binsearch(collection, key) do 
    binsearch(collection, key, 1, length(collection)) 
    end 

    defp binsearch(_collection, _key, low, hi) when hi < low do 
    -1 
    end 

    defp binsearch(collection, key, low, hi) do 
    mid = div(low + hi, 2) 
    item = Enum.at(collection, mid) 
    binsearch(collection, key, item, low, mid, hi) 
    end 

    defp binsearch(collection, key, item, low, mid, _hi) when key < item do 
    binsearch(collection, key, low, mid-1) 
    end 

    defp binsearch(collection, key, item, _low, mid, hi) when key > item do 
    binsearch(collection, key, mid+1, hi) 
    end 

    defp binsearch(_collection, _key, _item, _low, mid, _hi) do 
    mid 
    end 
end 
+0

Спасибо за подробный ответ. Да, переключение cond для защитных предложений может немного усложниться. – davidcunha

+1

Двоичный поиск эффективен только в том случае, если коллекция имеет O (1) поиск. 'Enum.at' работает в линейном времени, поэтому этот двоичный поиск медленнее, чем простой линейный поиск –

+0

Спасибо, очень хорошая точка. Я был на своих ранних шагах с Эликсиром, когда я написал ответ и, вероятно, пропустил это, потому что я сосредоточился на сопоставлении с образцом. –

5

Вы не можете сделать это с помощью сопоставления с образцом. Тем не менее, вы можете использовать cond который походит на Erlang if:

cond do 
    actual == guessed_number -> 
     ... 
    actual > guessed_number -> 
     ... 
    actual < guessed_number -> 
     ... 
end 
+0

Я также пробовал этот подход, который, на мой взгляд, действителен, но не то, что я искал. Спасибо в любом случае – davidcunha