Mi a legjobb módja annak, hogy értéket találjon egy gyűjteményben az Elixirben? Ha hozzászokott egy nem működő nyelvhez, például a C-hez vagy a JavaScript-hez, akkor érdemes lehet for-loopot használni. De az Elixir funkcionális természete azt jelenti, hogy más megközelítést kell alkalmaznunk: az Enum.find függvényt.

Az Enum.find függvény (és barátai Enum.find_index és Enum.find_value) minden olyan típuson működik, amely megvalósítja a Enumerable protokoll, leginkább a Lista, Térkép és Tartomány. A cikkben szereplő példák esetében az egyszerű listáknál maradunk.

Egyszerű érték megtalálása

Ha egy Enumerable-on belül szeretne értéket keresni, az Enum.find függvényt hívjuk meg az enumberble adatokkal és egy keresőfüggvénnyel:

e = [5, 10, 15]
Enum.find(e, fn v -> v == 10 end)
=> 10

Ha a keresett érték nem található, akkor helyette null értéket kapunk:

e = [5, 10, 15]
Enum.find(e, &(&1 == 11))
=> nil

Index keresése: Enum.find_index

Ha arra vagyunk kíváncsiak, milyen pozícióban jelenik meg egy elem a felsorolásban, használhatjuk az Enum.find_index:

e = [5, 10, 15]
Enum.find_index(e, fn v -> v == 10 end)
=> 1

Keresés a Térkép segítségével

Amikor meghívjuk az Enum.find függvényt egy térképpel, akkor egy kulcsot és egy, a kereső függvényünknek átadott értéket tartalmazó sort kapunk:

e = %{a: 5, b: 10, c: 15}
Enum.find(e, fn {k, v} -> k == :b end)
=> {:b, 10}

(Megjegyzés: mivel nem használjuk a v értéket a sorból, előfordulhat, hogy figyelmeztetést kapunk a nem használt változóra. Valójában _v nevet kellett volna adni, de hagytuk csak illusztrációs célból).

A visszaadott érték természetesen szintén egy sor, amely tartalmazza a kulcsot és az értéket is. Lehet, hogy nem ezt szeretnéd, de az Enum.find_value következő szakasza segíteni fog nekünk.

Érték keresése és átalakítása: Enum.find_value

Az előző példánkban visszakaptunk egy kulcsot és egy értéket képviselő sort, de mi van akkor, ha valójában csak egy elemet akarunk a sorból? Használhatjuk az Enum.find_value értéket:

e = %{a: 5, b: 10, c: 15}
Enum.find_value(e, fn {k, v} -> if k == :b, do: v, else: nil end)
=> v

Keresés a Capture Operator segítségével (&)

Az eddig használt összes példában így írtuk ki a tesztfüggvényünket:

fn v -> some_test(v) end

De van egy rövidítés, amelyet a rögzítési operátorral (&) használhatunk. A fenti függvényt átírhatjuk így:

&some_test(&1)

Itt a függvény argumentumai &1, &2, stb.-ként vannak rögzítve, báraz Enum.find esetén a kereső függvény csak egyetlen argumentumot vesz fel. Tehát, hogy átírjuk az egyik korábbi példánkat:

e = [5, 10, 15]
Enum.find(e, &(&1 == 10))
=> 10

Bónusz: Hogyan építsd fel a keresést a semmiből

Azzal kezdtük, hogy megemlítettük, hogy egyes nyelvek for-loop-ot használnak ennek a funkciónak a megvalósításához, és helyette az Enum.find-et kellene használnunk. De nem akarjuk azt a látszatot kelteni, hogy az Enum.find valamiféle varázslatos fekete doboz. Nézzük meg, hogyan tudtuk megvalósítani ezt a funkciót az Elixirben.

Az alábbi megvalósításunk a rekurziót, egy általános funkcionális mintát használ ciklus helyett, hogy értéket találjon a listán belül. Az egyszerűség kedvéért ebben a példában figyelmen kívül hagyjuk a többi felsorolható elemet.

Egy másik gyakori Elixir idiómát is használ, amely a mintaillesztés a függvénybemeneten: ha a lista üres, a válasz mindig nulla. Ellenkező esetben a lista első elemét (v) mintázatosan egyeztetjük a lista többi részével. Ha a v érték tesztje megegyezik, megtaláltuk a választ – ellenkező esetben rekurzív módon hívjuk meg:

defmodule ListUtil do
  def find([], _), do
    nil
  end
  def find([v | rest], f) do
    # invoke the test function on the first value in the list
    if f.(v),  do: v, else: find(rest, f)
  end
end
# test our implementation
ListUtil.find([1,2,3], fn i -> i == 2 end)

És ez az! Bár az idő nagy részében megteheti, amire szüksége van az Enum.find segítségével, jó, ha megérti, hogyan kell megközelíteni az Elixir ilyen jellegű problémáját, ha valamilyen más típusú adatszerkezeten át kell ismételni.

Eredetileg a Blixtdev oldalon tették közzé.

Jonathan több mint 20 éves mérnöki vezetői tapasztalattal rendelkezik kis és nagy startupoknál. Ha tetszik ez a cikk, csatlakozzon a Mediumhoz, hogy támogassa Jonathant és több ezer más szerzőt.